diff --git a/front/cypress/e2e/routes/dashboard/Dashboard.cy.js b/front/cypress/e2e/routes/dashboard/Dashboard.cy.js index bf9b464e0d..626bd29aaa 100644 --- a/front/cypress/e2e/routes/dashboard/Dashboard.cy.js +++ b/front/cypress/e2e/routes/dashboard/Dashboard.cy.js @@ -22,7 +22,8 @@ describe('Dashboard', () => { .should('have.class', 'btn-primary') .click(); - cy.url().should('eq', `${Cypress.config().baseUrl}/dashboard/my-new-dashboard/edit`); + // The selector of a new dashboard ends with 4 random characters, like scenes + cy.url().should('match', new RegExp(`^${Cypress.config().baseUrl}/dashboard/my-new-dashboard-[a-z0-9]{4}/edit$`)); }); it('Should add new boxes', () => { cy.contains('.btn-primary', 'dashboard.addBoxButton').click(); diff --git a/server/lib/dashboard/dashboard.create.js b/server/lib/dashboard/dashboard.create.js index 66c0a62b2a..185da4acc9 100644 --- a/server/lib/dashboard/dashboard.create.js +++ b/server/lib/dashboard/dashboard.create.js @@ -1,4 +1,5 @@ const db = require('../../models'); +const { slugify } = require('../../utils/slugify'); /** * @description Create a new dashboard. @@ -26,7 +27,18 @@ async function create(userId, dashboard) { if (dashboardWithTheHighestPosition.length > 0) { dashboard.position = dashboardWithTheHighestPosition[0].position + 1; } - return db.Dashboard.create({ ...dashboard, user_id: userId }); + let dashboardWithSelector = dashboard; + // Like scenes, the selector of a new dashboard gets random characters at the + // end so two dashboards with names sharing the same slug don't collide. + // A selector explicitly given by the caller is always kept as is, and + // existing dashboards keep the selector they were created with. + if (!dashboard.selector && dashboard.name) { + dashboardWithSelector = { + ...dashboard, + selector: slugify(dashboard.name, true), + }; + } + return db.Dashboard.create({ ...dashboardWithSelector, user_id: userId }); } module.exports = { diff --git a/server/test/lib/dashboard/dashboard.create.test.js b/server/test/lib/dashboard/dashboard.create.test.js index 781b2a5c11..37ce0bb9bd 100644 --- a/server/test/lib/dashboard/dashboard.create.test.js +++ b/server/test/lib/dashboard/dashboard.create.test.js @@ -5,7 +5,7 @@ const Dashboard = require('../../../lib/dashboard'); describe('dashboard.create', () => { const dashboard = new Dashboard(); - it('should create a dashboard', async () => { + it('should create a dashboard with a random selector', async () => { const newDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { name: 'My new dashboard', type: DASHBOARD_TYPE.MAIN, @@ -20,7 +20,46 @@ describe('dashboard.create', () => { ], }); expect(newDashboard).to.have.property('name', 'My new dashboard'); - expect(newDashboard).to.have.property('selector', 'my-new-dashboard'); + // selector should be the slug of the name + a dash + 4 random characters + expect(newDashboard.selector).to.match(/^my-new-dashboard-[a-z0-9]{4}$/); + }); + it('should create a dashboard with the selector given', async () => { + const newDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { + name: 'My dashboard with a custom selector', + selector: 'my-custom-dashboard-selector', + type: DASHBOARD_TYPE.MAIN, + position: 0, + visibility: DASHBOARD_VISIBILITY.PRIVATE, + boxes: [[]], + }); + expect(newDashboard).to.have.property('selector', 'my-custom-dashboard-selector'); + }); + it('should create two dashboards with names sharing the same slug', async () => { + const firstDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { + name: 'Salon', + type: DASHBOARD_TYPE.MAIN, + position: 0, + visibility: DASHBOARD_VISIBILITY.PRIVATE, + boxes: [[]], + }); + const secondDashboard = await dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { + name: 'SalĂ´n', + type: DASHBOARD_TYPE.MAIN, + position: 0, + visibility: DASHBOARD_VISIBILITY.PRIVATE, + boxes: [[]], + }); + expect(firstDashboard.selector).to.contain('salon'); + expect(secondDashboard.selector).to.contain('salon'); + expect(firstDashboard.selector).to.not.equal(secondDashboard.selector); + }); + it('should return error, missing name', async () => { + const promise = dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { + type: DASHBOARD_TYPE.MAIN, + visibility: DASHBOARD_VISIBILITY.PRIVATE, + boxes: [[]], + }); + return assert.isRejected(promise); }); it('should return error, missing box type', async () => { const promise = dashboard.create('0cd30aef-9c4e-4a23-88e3-3547971296e5', { diff --git a/server/test/lib/dashboard/dashboard.updateOrder.test.js b/server/test/lib/dashboard/dashboard.updateOrder.test.js index a58babb872..c2a5c36fe4 100644 --- a/server/test/lib/dashboard/dashboard.updateOrder.test.js +++ b/server/test/lib/dashboard/dashboard.updateOrder.test.js @@ -39,7 +39,7 @@ describe('dashboard.updateOrder', () => { raw: true, }); expect(dashboardsInNewOrder).to.deep.equal([ - { selector: 'my-new-dashboard', position: 0 }, + { selector: newDashboard.selector, position: 0 }, { selector: 'test-dashboard', position: 1 }, { selector: 'my-new-public-dashoard', position: 2 }, ]);