From b3b31be65575810c295c6928723d795802ff48b7 Mon Sep 17 00:00:00 2001 From: David Inga Date: Tue, 19 Sep 2023 13:53:38 +0200 Subject: [PATCH 1/6] removing fixtures for a real e2e based on api data removing fixtures gradually --- client/cypress/e2e/analysis/charts.cy.ts | 2 +- client/cypress/e2e/analysis/comparison.cy.ts | 2 +- .../{map.cy.ts => contextual-layer.cy.ts} | 2 +- client/cypress/e2e/analysis/filters.cy.ts | 157 ++++++++++-------- .../cypress/e2e/analysis/impact-layer.cy.ts | 31 ++++ client/cypress/e2e/analysis/scenarios.cy.ts | 2 +- client/cypress/e2e/analysis/table.cy.ts | 2 +- client/cypress/e2e/analysis/ui.cy.ts | 2 +- client/cypress/e2e/data.cy.ts | 2 +- .../cypress/e2e/data/download-template.cy.ts | 32 ++++ client/cypress/e2e/data/table.cy.ts | 23 +++ .../cypress/e2e/intervention-creation.cy.ts | 2 +- client/cypress/e2e/intervention-edition.cy.ts | 2 +- client/cypress/e2e/scenario-creation.cy.ts | 2 +- client/cypress/e2e/scenarios.cy.ts | 2 +- client/cypress/e2e/sign-in.cy.ts | 2 +- client/cypress/support/commands.ts | 20 +++ client/cypress/support/index.d.ts | 1 + .../containers/admin/data-table/component.tsx | 5 +- 19 files changed, 207 insertions(+), 86 deletions(-) rename client/cypress/e2e/analysis/{map.cy.ts => contextual-layer.cy.ts} (98%) create mode 100644 client/cypress/e2e/analysis/impact-layer.cy.ts create mode 100644 client/cypress/e2e/data/download-template.cy.ts create mode 100644 client/cypress/e2e/data/table.cy.ts diff --git a/client/cypress/e2e/analysis/charts.cy.ts b/client/cypress/e2e/analysis/charts.cy.ts index 1964e4f91..b80e1f806 100644 --- a/client/cypress/e2e/analysis/charts.cy.ts +++ b/client/cypress/e2e/analysis/charts.cy.ts @@ -1,7 +1,7 @@ describe('Analysis charts', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/analysis/chart'); }); diff --git a/client/cypress/e2e/analysis/comparison.cy.ts b/client/cypress/e2e/analysis/comparison.cy.ts index eeff79683..937ce5c5e 100644 --- a/client/cypress/e2e/analysis/comparison.cy.ts +++ b/client/cypress/e2e/analysis/comparison.cy.ts @@ -1,7 +1,7 @@ describe('Analysis comparison', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); }); afterEach(() => { diff --git a/client/cypress/e2e/analysis/map.cy.ts b/client/cypress/e2e/analysis/contextual-layer.cy.ts similarity index 98% rename from client/cypress/e2e/analysis/map.cy.ts rename to client/cypress/e2e/analysis/contextual-layer.cy.ts index 06dea946f..f48702edc 100644 --- a/client/cypress/e2e/analysis/map.cy.ts +++ b/client/cypress/e2e/analysis/contextual-layer.cy.ts @@ -1,7 +1,7 @@ describe('Analysis contextual layers', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/analysis/map'); cy.wait(['@fetchIndicators', '@fetchContextualLayerCategories']); cy.get('[data-testid="contextual-layer-modal-toggle"]').click(); diff --git a/client/cypress/e2e/analysis/filters.cy.ts b/client/cypress/e2e/analysis/filters.cy.ts index db65502ee..456e08c24 100644 --- a/client/cypress/e2e/analysis/filters.cy.ts +++ b/client/cypress/e2e/analysis/filters.cy.ts @@ -1,7 +1,7 @@ describe('Analysis filters', () => { beforeEach(() => { - cy.interceptAllRequests(); - cy.login(); + // cy.interceptAllRequests(); + cy.loginWithFixtures(); cy.visit('/analysis/table'); }); @@ -9,90 +9,103 @@ describe('Analysis filters', () => { cy.logout(); }); - it('should be able to select all indicator', () => { - cy.wait('@fetchIndicators').then((interception) => { - expect(interception.response.body?.data).have.length(5); - }); + // it('should be able to select all indicator', () => { + // cy.wait('@fetchIndicators').then((interception) => { + // expect(interception.response.body?.data).have.length(5); + // }); - cy.url().should('not.include', 'indicator'); + // cy.url().should('not.include', 'indicator'); - // select indicator - cy.get('[data-testid="select-indicators-filter"]').find('button').click(); - cy.get('[data-testid="select-indicators-filter"] ul li:first').click(); + // // select indicator + // cy.get('[data-testid="select-indicators-filter"]').find('button').click(); + // cy.get('[data-testid="select-indicators-filter"] ul li:first').click(); - cy.url().should('include', 'indicator=all'); - }); + // cy.url().should('include', 'indicator=all'); + // }); - it('should be able to select Land use indicator', () => { - cy.wait('@fetchIndicators').then((interception) => { - expect(interception.response.body?.data).have.length(5); - }); + // it('should be able to filter by Land use indicator', () => { + // cy.wait('@fetchIndicators').then((interception) => { + // expect(interception.response.body?.data).have.length(5); + // }); - cy.url().should('not.include', 'indicator'); + // cy.url().should('not.include', 'indicator'); - cy.get('[data-testid="select-indicators-filter"]').find('button').click(); - cy.get('[data-testid="select-indicators-filter"] ul li:first').next().click(); + // cy.get('[data-testid="select-indicators-filter"]').find('button').click(); + // cy.get('[data-testid="select-indicators-filter"] ul li:first').next().click(); - cy.url().should('include', 'indicator=5c595ac7-f144-485f-9f32-601f6faae9fe'); // Land use - }); + // cy.url().should('include', 'indicator=5c595ac7-f144-485f-9f32-601f6faae9fe'); // Land use + // }); + + it('should be able to filter by a material', () => { + cy.intercept('GET', '/api/v1/materials/trees*').as('materialsTrees'); - it('should update the params playing with the filters', () => { - // Step 1: open more filters cy.get('[data-testid="more-filters-button"]').click(); - cy.wait(['@materialsTrees', '@originsTrees', '@t1Suppliers', '@fetchImpactTable']); - - // Adding new interceptors after selecting a filter - cy.intercept( - 'GET', - '/api/v1/suppliers/types?*originIds[]=8bd7e578-f64f-4042-8a3a-2a7652ce850b*', - { - fixture: 'trees/suppliers-filtered.json', - }, - ).as('t1SuppliersFiltered'); - - cy.intercept( - { - method: 'GET', - pathname: '/api/v1/materials/trees', - query: { - 'supplierIds[]': 'c8bca40d-1aec-44e3-b82b-8170898800ad', - }, - }, - { - fixture: 'trees/materials-filtered.json', - }, - ).as('materialsTreesFiltered'); - cy.wait('@locationTypes'); - - // Step 2: Selecting Angola in the admin regions selector - cy.get('[data-testid="tree-select-origins-filter"]').find('div[role="combobox"]').click(); - cy.get('[data-testid="tree-select-origins-filter"]') - .find('div[role="listbox"]') - .find('.rc-tree-treenode') - .eq(1) - .click(); - cy.get('[data-testid="tree-select-origins-filter"]') - .find('input:visible:first') - .type('{enter}'); - cy.wait('@locationTypes'); - // Step 3: Selecting Moll in the material selector - cy.wait('@t1SuppliersFiltered'); + cy.wait('@materialsTrees'); cy.get('[data-testid="tree-select-t1-suppliers-filter"]').find('div[role="combobox"]').click(); cy.get('[data-testid="tree-select-t1-suppliers-filter"]') .find('div[role="listbox"]') .find('.rc-tree-treenode') .eq(1) .click(); - cy.wait('@locationTypes'); - // Step 4: Checking material selector - cy.wait('@materialsTreesFiltered') - .its('request.url') - .should('include', '8bd7e578-f64f-4042-8a3a-2a7652ce850b'); - - cy.get('[data-testid="tree-select-materials-filter"]').find('div[role="combobox"]').click(); - cy.get('[data-testid="tree-select-materials-filter"]') - .find('div[role="listbox"]') - .find('.rc-tree-treenode:visible') - .should('have.length', 1); // first treenode is empty }); + + // it('should update the URL params selecting multiple filters', () => { + // // Step 1: open more filters + // cy.get('[data-testid="more-filters-button"]').click(); + // cy.wait(['@materialsTrees', '@originsTrees', '@t1Suppliers', '@fetchImpactTable']); + + // // Adding new interceptors after selecting a filter + // cy.intercept( + // 'GET', + // '/api/v1/suppliers/types?*originIds[]=8bd7e578-f64f-4042-8a3a-2a7652ce850b*', + // { + // fixture: 'trees/suppliers-filtered.json', + // }, + // ).as('t1SuppliersFiltered'); + + // cy.intercept( + // { + // method: 'GET', + // pathname: '/api/v1/materials/trees', + // query: { + // 'supplierIds[]': 'c8bca40d-1aec-44e3-b82b-8170898800ad', + // }, + // }, + // { + // fixture: 'trees/materials-filtered.json', + // }, + // ).as('materialsTreesFiltered'); + // cy.wait('@locationTypes'); + + // // Step 2: Selecting Angola in the admin regions selector + // cy.get('[data-testid="tree-select-origins-filter"]').find('div[role="combobox"]').click(); + // cy.get('[data-testid="tree-select-origins-filter"]') + // .find('div[role="listbox"]') + // .find('.rc-tree-treenode') + // .eq(1) + // .click(); + // cy.get('[data-testid="tree-select-origins-filter"]') + // .find('input:visible:first') + // .type('{enter}'); + // cy.wait('@locationTypes'); + // // Step 3: Selecting Moll in the material selector + // cy.wait('@t1SuppliersFiltered'); + // cy.get('[data-testid="tree-select-t1-suppliers-filter"]').find('div[role="combobox"]').click(); + // cy.get('[data-testid="tree-select-t1-suppliers-filter"]') + // .find('div[role="listbox"]') + // .find('.rc-tree-treenode') + // .eq(1) + // .click(); + // cy.wait('@locationTypes'); + // // Step 4: Checking material selector + // cy.wait('@materialsTreesFiltered') + // .its('request.url') + // .should('include', '8bd7e578-f64f-4042-8a3a-2a7652ce850b'); + + // cy.get('[data-testid="tree-select-materials-filter"]').find('div[role="combobox"]').click(); + // cy.get('[data-testid="tree-select-materials-filter"]') + // .find('div[role="listbox"]') + // .find('.rc-tree-treenode:visible') + // .should('have.length', 1); // first treenode is empty + // }); }); diff --git a/client/cypress/e2e/analysis/impact-layer.cy.ts b/client/cypress/e2e/analysis/impact-layer.cy.ts new file mode 100644 index 000000000..583c86016 --- /dev/null +++ b/client/cypress/e2e/analysis/impact-layer.cy.ts @@ -0,0 +1,31 @@ +describe('Analysis: map impact layer', () => { + beforeEach(() => { + cy.intercept('GET', '/api/v1/h3/map/impact*', { + fixture: 'layers/impact-layer.json', + }).as('fetchImpactMap'); + cy.login(); + }); + + afterEach(() => { + cy.logout(); + }); + + /** + * We're assuming mapbox is working as expected, and we'll just check that the request is made + */ + it('request the impact layer', () => { + cy.visit('/analysis/map'); + + cy.get('canvas.mapboxgl-canvas').should('be.visible'); + + cy.wait('@fetchImpactMap').then((interception) => { + cy.wrap(JSON.stringify(interception.response.body.data[0])).should( + 'be.equal', + JSON.stringify({ + h: '84df6b7ffffffff', + v: '26924145.89', + }), + ); + }); + }); +}); diff --git a/client/cypress/e2e/analysis/scenarios.cy.ts b/client/cypress/e2e/analysis/scenarios.cy.ts index 9bce1dc8a..11eede9db 100644 --- a/client/cypress/e2e/analysis/scenarios.cy.ts +++ b/client/cypress/e2e/analysis/scenarios.cy.ts @@ -1,7 +1,7 @@ describe('Analysis scenarios', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); }); afterEach(() => { diff --git a/client/cypress/e2e/analysis/table.cy.ts b/client/cypress/e2e/analysis/table.cy.ts index 96bba1d12..49a1c1936 100644 --- a/client/cypress/e2e/analysis/table.cy.ts +++ b/client/cypress/e2e/analysis/table.cy.ts @@ -6,7 +6,7 @@ import { describe('Analysis table', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/analysis/table'); }); diff --git a/client/cypress/e2e/analysis/ui.cy.ts b/client/cypress/e2e/analysis/ui.cy.ts index b8c6114f1..2f3dfbb5d 100644 --- a/client/cypress/e2e/analysis/ui.cy.ts +++ b/client/cypress/e2e/analysis/ui.cy.ts @@ -1,7 +1,7 @@ describe('Analysis tab', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/analysis'); }); diff --git a/client/cypress/e2e/data.cy.ts b/client/cypress/e2e/data.cy.ts index 2f16fac39..af0febad3 100644 --- a/client/cypress/e2e/data.cy.ts +++ b/client/cypress/e2e/data.cy.ts @@ -43,7 +43,7 @@ describe('Data page - admin', () => { describe('Data page - user', () => { beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/data'); cy.wait('@sourcingLocations'); }); diff --git a/client/cypress/e2e/data/download-template.cy.ts b/client/cypress/e2e/data/download-template.cy.ts new file mode 100644 index 000000000..464aaa9cf --- /dev/null +++ b/client/cypress/e2e/data/download-template.cy.ts @@ -0,0 +1,32 @@ +describe('Download data template', () => { + beforeEach(() => { + cy.login(); + }); + + afterEach(() => { + cy.logout(); + }); + + it('clicking on Download template in the upload modal', () => { + cy.intercept('/files/data-template.xlsx').as('downloadDataTemplate'); + + cy.visit('/data'); + + // Opening upload modal + cy.get('[data-testid="upload-data-source-btn"]').click(); + cy.get('[data-testid="modal-upload-data-source"]').should('be.visible'); + + cy.get('[data-testid="download-template-btn"]').should('have.attr', 'download'); + cy.get('[data-testid="download-template-btn"]') + .should('have.attr', 'href') + .and('equal', '/files/data-template.xlsx'); + cy.get('[data-testid="download-template-btn"]').click(); + + cy.wait('@downloadDataTemplate').then((interception) => { + expect(interception.response.statusCode).to.equal(200); + expect(interception.response.headers['content-type']).to.equal( + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + ); + }); + }); +}); diff --git a/client/cypress/e2e/data/table.cy.ts b/client/cypress/e2e/data/table.cy.ts new file mode 100644 index 000000000..6a1ef9988 --- /dev/null +++ b/client/cypress/e2e/data/table.cy.ts @@ -0,0 +1,23 @@ +describe('Data ingestion: table visualization', () => { + beforeEach(() => { + cy.intercept('GET', '/api/v1/sourcing-locations/materials*').as('sourcingLocationsMaterials'); + cy.login(); + cy.visit('/data'); + }); + + afterEach(() => { + cy.logout(); + }); + + it('see data ingested in a table', () => { + cy.wait('@sourcingLocationsMaterials').then((interception) => { + cy.get('table').should('be.visible'); + // based on data and pagination, there should be more than 50 rows in the table + cy.get('tr.group').should('have.length', interception.response.body?.meta.size); + }); + }); + + it('no filters in the table', () => { + cy.get('[data-testid="search-name-scenario"]').should('be.disabled'); + }); +}); diff --git a/client/cypress/e2e/intervention-creation.cy.ts b/client/cypress/e2e/intervention-creation.cy.ts index 1375af529..a5483bdd8 100644 --- a/client/cypress/e2e/intervention-creation.cy.ts +++ b/client/cypress/e2e/intervention-creation.cy.ts @@ -11,7 +11,7 @@ beforeEach(() => { fixture: 'scenario/scenario-materials', }).as('materialsTrees'); - cy.login(); + cy.loginWithFixtures(); cy.createScenario(); cy.visit('/data/scenarios/some-random-id/interventions/new'); }); diff --git a/client/cypress/e2e/intervention-edition.cy.ts b/client/cypress/e2e/intervention-edition.cy.ts index 521f611d6..dfa319781 100644 --- a/client/cypress/e2e/intervention-edition.cy.ts +++ b/client/cypress/e2e/intervention-edition.cy.ts @@ -1,7 +1,7 @@ beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/data/scenarios/some-random-id/interventions/random-intervention-id/edit'); }); diff --git a/client/cypress/e2e/scenario-creation.cy.ts b/client/cypress/e2e/scenario-creation.cy.ts index 17b8343f0..2e7c301b9 100644 --- a/client/cypress/e2e/scenario-creation.cy.ts +++ b/client/cypress/e2e/scenario-creation.cy.ts @@ -1,6 +1,6 @@ beforeEach(() => { cy.interceptAllRequests(); - cy.login(); + cy.loginWithFixtures(); cy.visit('/data/scenarios/new'); }); diff --git a/client/cypress/e2e/scenarios.cy.ts b/client/cypress/e2e/scenarios.cy.ts index 3a488695c..3d89a42a9 100644 --- a/client/cypress/e2e/scenarios.cy.ts +++ b/client/cypress/e2e/scenarios.cy.ts @@ -24,7 +24,7 @@ beforeEach(() => { // statusCode: 200, // }).as('deleteScenario'); - cy.login(); + cy.loginWithFixtures(); cy.visit('/data/scenarios'); }); diff --git a/client/cypress/e2e/sign-in.cy.ts b/client/cypress/e2e/sign-in.cy.ts index 1a9fc996a..dbf955da7 100644 --- a/client/cypress/e2e/sign-in.cy.ts +++ b/client/cypress/e2e/sign-in.cy.ts @@ -8,7 +8,7 @@ describe('Sign in', () => { cy.visit('/auth/signin'); cy.get('[name="email"]').type(Cypress.env('USERNAME')); cy.get('[name="password"]').type(Cypress.env('PASSWORD')); - cy.get('#signInForm').submit(); + cy.get('button[type="submit"]').click(); cy.wait('@signInRequest'); cy.url().should('contain', 'analysis'); }); diff --git a/client/cypress/support/commands.ts b/client/cypress/support/commands.ts index f1f416366..4c1e6b095 100644 --- a/client/cypress/support/commands.ts +++ b/client/cypress/support/commands.ts @@ -18,6 +18,26 @@ Cypress.Commands.add( } = {}): Cypress.Chainable => { cy.log('🔐 Sign in with Next Auth'); + return cy.session(['login', username, password], () => { + cy.wrap( + signIn('credentials', { + redirect: false, + username, + password, + }), + ); + }); + }, +); + +Cypress.Commands.add( + 'loginWithFixtures', + ({ + username = Cypress.env('USERNAME'), + password = Cypress.env('PASSWORD'), + } = {}): Cypress.Chainable => { + cy.log('🔐 Sign in with Next Auth'); + cy.intercept('GET', '/api/auth/session', { fixture: 'auth/session.json', }).as('session'); diff --git a/client/cypress/support/index.d.ts b/client/cypress/support/index.d.ts index 279008554..984b03212 100644 --- a/client/cypress/support/index.d.ts +++ b/client/cypress/support/index.d.ts @@ -10,6 +10,7 @@ declare global { * @example cy.login() */ login(credentials?: { username?: string; password?: string }): Chainable; + loginWithFixtures(credentials?: { username?: string; password?: string }): Chainable; logout(): Chainable; createScenario(): Chainable; interceptAllRequests(): Chainable; diff --git a/client/src/containers/admin/data-table/component.tsx b/client/src/containers/admin/data-table/component.tsx index cc781f988..9e691759f 100644 --- a/client/src/containers/admin/data-table/component.tsx +++ b/client/src/containers/admin/data-table/component.tsx @@ -168,7 +168,7 @@ const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => { - {task?.user?.email === session.user?.email && } + {task?.user?.email === session?.user?.email && } {!isSourcingLocationsLoading && (
@@ -214,7 +214,7 @@ const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => { onDismiss={closeUploadDataSourceModal} theme="default" > -
+

Uploading a new file will replace all the current data. @@ -233,6 +233,7 @@ const AdminDataPage: React.FC<{ task: Task }> = ({ task }) => { rel="noopener noreferrer" icon={

From 78edadf5361e402039d3ce0f5f1a83c8d8799640 Mon Sep 17 00:00:00 2001 From: David Inga Date: Thu, 21 Sep 2023 09:30:03 +0200 Subject: [PATCH 6/6] fixed profile form updated password --- client/CHANGELOG.md | 8 +++++- client/cypress/e2e/profile.cy.ts | 22 +++++++++++++++ .../update-password-form/component.tsx | 28 +++++++++++++------ 3 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 client/cypress/e2e/profile.cy.ts diff --git a/client/CHANGELOG.md b/client/CHANGELOG.md index d813a8537..8be1fc18a 100644 --- a/client/CHANGELOG.md +++ b/client/CHANGELOG.md @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/). -## [v0.6.0 Unreleased] +## [Unreleased] + +### Fixed + +- Update password in profile form was not working as expected [LANDGRIF-1479](https://vizzuality.atlassian.net/browse/LANDGRIF-1479) + +## [v1.0.0] ### Added diff --git a/client/cypress/e2e/profile.cy.ts b/client/cypress/e2e/profile.cy.ts new file mode 100644 index 000000000..4ea791705 --- /dev/null +++ b/client/cypress/e2e/profile.cy.ts @@ -0,0 +1,22 @@ +describe('Profile', () => { + beforeEach(() => { + cy.login(); + }); + + afterEach(() => { + cy.logout(); + }); + + it('change password', () => { + cy.intercept('PATCH', '/api/v1/users/me/password', { + statusCode: 200, + body: {}, + }).as('updatePasswordRequest'); + cy.visit('/profile'); + + cy.get('[name="currentPassword"]').type(Cypress.env('PASSWORD')); + cy.get('[name="newPassword"]').type(Cypress.env('PASSWORD')); + cy.get('[name="passwordConfirmation"]').type(Cypress.env('PASSWORD')); + cy.get('button[data-testid="submit-update-password"]').click(); + }); +}); diff --git a/client/src/containers/update-password-form/component.tsx b/client/src/containers/update-password-form/component.tsx index 887244029..fcf82e653 100644 --- a/client/src/containers/update-password-form/component.tsx +++ b/client/src/containers/update-password-form/component.tsx @@ -32,15 +32,22 @@ const UserPasswordForm: React.FC = () => { const handleEditPassword = useCallback( (data: PasswordPayload) => { - updatePassword.mutate(data, { - onSuccess: () => { - toast.success('Your changes were successfully saved.'); + updatePassword.mutate( + { + // avoid passing passwordConfirmation to the API + currentPassword: data.currentPassword, + newPassword: data.newPassword, }, - onError: (error: ErrorResponse) => { - const { errors } = error.response?.data; - errors.forEach(({ title }) => toast.error(title)); + { + onSuccess: () => { + toast.success('Your changes were successfully saved.'); + }, + onError: (error: ErrorResponse) => { + const { errors } = error.response?.data; + errors.forEach(({ title }) => toast.error(title)); + }, }, - }); + ); }, [updatePassword], ); @@ -83,7 +90,12 @@ const UserPasswordForm: React.FC = () => {
-