diff --git a/after-drag.png b/after-drag.png deleted file mode 100644 index d2d4ee4..0000000 Binary files a/after-drag.png and /dev/null differ diff --git a/before-drag.png b/before-drag.png deleted file mode 100644 index 75e513c..0000000 Binary files a/before-drag.png and /dev/null differ diff --git a/full-page-screenshot.png b/full-page-screenshot.png deleted file mode 100644 index 767751f..0000000 Binary files a/full-page-screenshot.png and /dev/null differ diff --git a/screenshots/after-pan-down.png b/screenshots/after-pan-down.png new file mode 100644 index 0000000..bf3ed1b Binary files /dev/null and b/screenshots/after-pan-down.png differ diff --git a/screenshots/after-scroll-down.png b/screenshots/after-scroll-down.png new file mode 100644 index 0000000..4c794f1 Binary files /dev/null and b/screenshots/after-scroll-down.png differ diff --git a/screenshots/after.png b/screenshots/after.png new file mode 100644 index 0000000..74b3039 Binary files /dev/null and b/screenshots/after.png differ diff --git a/screenshots/before.png b/screenshots/before.png new file mode 100644 index 0000000..4ba8f2c Binary files /dev/null and b/screenshots/before.png differ diff --git a/screenshots/final-screenshot.png b/screenshots/final-screenshot.png new file mode 100644 index 0000000..52707e5 Binary files /dev/null and b/screenshots/final-screenshot.png differ diff --git a/screenshots/final-state.png b/screenshots/final-state.png new file mode 100644 index 0000000..e06f2d5 Binary files /dev/null and b/screenshots/final-state.png differ diff --git a/screenshots/final.png b/screenshots/final.png new file mode 100644 index 0000000..ea8d924 Binary files /dev/null and b/screenshots/final.png differ diff --git a/screenshots/fully-zoomed-out.png b/screenshots/fully-zoomed-out.png new file mode 100644 index 0000000..4ba8f2c Binary files /dev/null and b/screenshots/fully-zoomed-out.png differ diff --git a/screenshots/initial-state.png b/screenshots/initial-state.png new file mode 100644 index 0000000..7e75dcb Binary files /dev/null and b/screenshots/initial-state.png differ diff --git a/screenshots/initial.png b/screenshots/initial.png new file mode 100644 index 0000000..920afaa Binary files /dev/null and b/screenshots/initial.png differ diff --git a/screenshots/progress-1.png b/screenshots/progress-1.png new file mode 100644 index 0000000..62b9d69 Binary files /dev/null and b/screenshots/progress-1.png differ diff --git a/screenshots/progress-2.png b/screenshots/progress-2.png new file mode 100644 index 0000000..0f86b60 Binary files /dev/null and b/screenshots/progress-2.png differ diff --git a/screenshots/progress-3.png b/screenshots/progress-3.png new file mode 100644 index 0000000..a3532b3 Binary files /dev/null and b/screenshots/progress-3.png differ diff --git a/screenshots/progress-4.png b/screenshots/progress-4.png new file mode 100644 index 0000000..5b98c9c Binary files /dev/null and b/screenshots/progress-4.png differ diff --git a/screenshots/walls-created-after-moving-canvas.png b/screenshots/walls-created-after-moving-canvas.png new file mode 100644 index 0000000..3a111ae Binary files /dev/null and b/screenshots/walls-created-after-moving-canvas.png differ diff --git a/screenshots/walls-created-fullscreen.png b/screenshots/walls-created-fullscreen.png new file mode 100644 index 0000000..9e7e465 Binary files /dev/null and b/screenshots/walls-created-fullscreen.png differ diff --git a/screenshots/walls-created.png b/screenshots/walls-created.png new file mode 100644 index 0000000..89295a7 Binary files /dev/null and b/screenshots/walls-created.png differ diff --git a/screenshots/walls-deleted-after-moving-canvas.png b/screenshots/walls-deleted-after-moving-canvas.png new file mode 100644 index 0000000..64a2460 Binary files /dev/null and b/screenshots/walls-deleted-after-moving-canvas.png differ diff --git a/screenshots/walls-deleted-fullscreen.png b/screenshots/walls-deleted-fullscreen.png new file mode 100644 index 0000000..72f875d Binary files /dev/null and b/screenshots/walls-deleted-fullscreen.png differ diff --git a/screenshots/walls-deleted.png b/screenshots/walls-deleted.png new file mode 100644 index 0000000..89cf82c Binary files /dev/null and b/screenshots/walls-deleted.png differ diff --git a/screenshots/zones-created-after-moving-canvas.png b/screenshots/zones-created-after-moving-canvas.png new file mode 100644 index 0000000..eaf6adf Binary files /dev/null and b/screenshots/zones-created-after-moving-canvas.png differ diff --git a/screenshots/zones-created-after-walls.png b/screenshots/zones-created-after-walls.png new file mode 100644 index 0000000..2fa8058 Binary files /dev/null and b/screenshots/zones-created-after-walls.png differ diff --git a/screenshots/zones-deleted-after-moving-canvas.png b/screenshots/zones-deleted-after-moving-canvas.png new file mode 100644 index 0000000..6b355af Binary files /dev/null and b/screenshots/zones-deleted-after-moving-canvas.png differ diff --git a/screenshots/zoomed-in.png b/screenshots/zoomed-in.png new file mode 100644 index 0000000..60c5f79 Binary files /dev/null and b/screenshots/zoomed-in.png differ diff --git a/simulation-screenshots/after-drawing.png b/simulation-screenshots/after-drawing.png new file mode 100644 index 0000000..b4a5572 Binary files /dev/null and b/simulation-screenshots/after-drawing.png differ diff --git a/simulation-screenshots/before-drawing.png b/simulation-screenshots/before-drawing.png new file mode 100644 index 0000000..38aa5cf Binary files /dev/null and b/simulation-screenshots/before-drawing.png differ diff --git a/simulation-screenshots/simulation-screenshot.png b/simulation-screenshots/simulation-screenshot.png new file mode 100644 index 0000000..65edd3f Binary files /dev/null and b/simulation-screenshots/simulation-screenshot.png differ diff --git a/tests/Builder.spec.js b/tests/Builder.spec.js new file mode 100644 index 0000000..ec7fee8 --- /dev/null +++ b/tests/Builder.spec.js @@ -0,0 +1,216 @@ +import { test, expect } from '@playwright/test'; +import fs from 'fs'; + +test('Create walls after moving canvas', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 4. Move the canvas to the top position + console.log('Moving canvas to the top position...'); + const canvas = page.locator('canvas').first(); + const canvasBox = await canvas.boundingBox(); + + if (!canvasBox) { + throw new Error('Canvas bounding box not found. Ensure the canvas is visible.'); + } + + // Start position (center of canvas) + const startX = canvasBox.x + canvasBox.width / 2; + const startY = canvasBox.y + canvasBox.height / 2; + + // Simulate a drag action to move the canvas + await page.mouse.move(startX, startY); + await page.mouse.down(); + + // Move the mouse down while dragging + await page.mouse.move(startX, startY + 100, { + steps: 20, // Smooth movement + }); + + // Simultaneously scroll the page (if needed) + await page.mouse.wheel(0, 500); // Scroll down 500px + + await page.mouse.up(); + + // 5. Select the wall tool + console.log('Selecting wall tool...'); + await page.getByTitle('Wall').getByRole('img').click(); + + await page.waitForTimeout(2000); // Wait for the wall tool to be active + + // 6. Draw walls using reusable function + const wallCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + await drawOrDeleteWalls(page, wallCoordinates, 'create'); + + // 7. Take a final screenshot after drawing walls + const afterPath = `${screenshotDir}/walls-created-after-moving-canvas.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +test('Delete walls after moving canvas', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 4. Move the canvas to the top position + console.log('Moving canvas to the top position...'); + const canvas = page.locator('canvas').first(); + const canvasBox = await canvas.boundingBox(); + + if (!canvasBox) { + throw new Error('Canvas bounding box not found. Ensure the canvas is visible.'); + } + + // Start position (center of canvas) + const startX = canvasBox.x + canvasBox.width / 2; + const startY = canvasBox.y + canvasBox.height / 2; + + // Simulate a drag action to move the canvas + await page.mouse.move(startX, startY); + await page.mouse.down(); + + // Move the mouse down while dragging + await page.mouse.move(startX, startY + 100, { + steps: 20, // Smooth movement + }); + + // Simultaneously scroll the page (if needed) + await page.mouse.wheel(0, 500); // Scroll down 500px + + await page.mouse.up(); + + // 5. Open the "3 dots" menu and select the delete tool + console.log('Opening three-dot menu...'); + await page.locator('.drop-down-option-button > svg').click(); + + console.log('Selecting Delete option...'); + await page.locator('div').filter({ hasText: /^Delete$/ }).first().click(); + + // Wait for the delete tool to be active + await page.waitForTimeout(2000); // Adjust timeout if necessary + + // 6. Define specific points for deletion, including midpoints + const deleteCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + // Add midpoints between consecutive points + const enhancedDeleteCoordinates = []; + for (let i = 0; i < deleteCoordinates.length - 1; i++) { + const currentPoint = deleteCoordinates[i]; + const nextPoint = deleteCoordinates[i + 1]; + + // Add the current point + enhancedDeleteCoordinates.push(currentPoint); + + // Calculate and add the midpoint + const midX = (currentPoint.x + nextPoint.x) / 2; + const midY = (currentPoint.y + nextPoint.y) / 2; + enhancedDeleteCoordinates.push({ x: midX, y: midY }); + } + + // Add the last point + enhancedDeleteCoordinates.push(deleteCoordinates[deleteCoordinates.length - 1]); + + // Delete walls using reusable function + await drawOrDeleteWalls(page, enhancedDeleteCoordinates, 'delete'); + + // 7. Take a final screenshot after deleting walls + const afterPath = `${screenshotDir}/walls-deleted-after-moving-canvas.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +/** + * Reusable function for creating or deleting walls. + * @param {Object} page - Playwright page object + * @param {Array} coordinates - Array of {x, y} objects representing wall points + * @param {String} action - 'create' or 'delete' + */ +async function drawOrDeleteWalls(page, coordinates, action) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} walls...`); + + for (const { x, y } of coordinates) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} at (${x}, ${y})`); + await simulatePointerClick(page, x, y); + + // Add a small delay between clicks to ensure proper interaction + await page.waitForTimeout(300); // Adjust timeout if necessary + } + + if (action === 'create') { + // Finalize wall creation with right-click + await simulatePointerClick(page, 100, 160, 'right'); // Right-click to finalize + } +} + +/** + * Simulates a pointer click at specific coordinates. + */ +async function simulatePointerClick(page, x, y, button = 'left') { + // Move to the desired position + await page.mouse.move(x, y); + + // Simulate mouse down and up to mimic a real click + await page.mouse.down({ button }); + await page.mouse.up({ button }); +} \ No newline at end of file diff --git a/tests/Builder.spec.js-snapshots/after-linux.png b/tests/Builder.spec.js-snapshots/after-linux.png new file mode 100644 index 0000000..76ac3df Binary files /dev/null and b/tests/Builder.spec.js-snapshots/after-linux.png differ diff --git a/tests/Builder.spec.js-snapshots/simulation-screenshots-after-drawing-linux.png b/tests/Builder.spec.js-snapshots/simulation-screenshots-after-drawing-linux.png new file mode 100644 index 0000000..b76edc8 Binary files /dev/null and b/tests/Builder.spec.js-snapshots/simulation-screenshots-after-drawing-linux.png differ diff --git a/tests/Delete.spec.js b/tests/Delete.spec.js new file mode 100644 index 0000000..5d32c0c --- /dev/null +++ b/tests/Delete.spec.js @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test'; + +test('Test delete functionality', async ({ page }) => { + // Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + + await page.locator('.drop-down-option-button > svg').click(); + await page.locator('div').filter({ hasText: /^Delete$/ }).first().click(); + + + await page.waitForTimeout(4000); +}); \ No newline at end of file diff --git a/tests/NewCreation.spec.js b/tests/NewCreation.spec.js new file mode 100644 index 0000000..e0911a5 --- /dev/null +++ b/tests/NewCreation.spec.js @@ -0,0 +1,24 @@ +import { test, expect } from '@playwright/test'; + +test('Login page', async ({ page }) => { + // Navigate to the login page + await page.goto('http://185.100.212.76:8200'); + // Navigate to the sign-up page + await page.getByText('Register here!').click(); + await page.waitForTimeout(3000); + await page.getByPlaceholder('Username').fill('RamkumarP'); + await page.getByPlaceholder('Email').fill('ramkumar1234567@testing.local'); + await page.getByPlaceholder('Password').fill('12345678'); + await page.locator('input[type="checkbox"]').first().check(); // Checks the first checkbox + await page.waitForTimeout(3000); + await page.getByRole('button', { name: 'Register', exact: true }).click(); + await page.waitForTimeout(2000); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.waitForTimeout(10000); + + await page.goto('http://185.100.212.76:8200/project'); + await page.waitForTimeout(10000); + + + +}); \ No newline at end of file diff --git a/tests/Visuvalization.spec.js b/tests/Visualization.spec.js similarity index 94% rename from tests/Visuvalization.spec.js rename to tests/Visualization.spec.js index 3ebd780..e895b6d 100644 --- a/tests/Visuvalization.spec.js +++ b/tests/Visualization.spec.js @@ -22,10 +22,11 @@ test('Visualization-Drag&Drop Page', async ({ page }) => { // Navigate to the application and log in await page.goto('http://185.100.212.76:8200'); - await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); await page.getByPlaceholder('Password').fill('123456'); await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.waitForTimeout(10000); // Wait for the page to load await page.getByText('Visualization').click(); await page.getByText('Zone 1').click(); diff --git a/tests/Visualizationtrack1.spec.js b/tests/Visualizationtrack1.spec.js new file mode 100644 index 0000000..2042c25 --- /dev/null +++ b/tests/Visualizationtrack1.spec.js @@ -0,0 +1,185 @@ +import { test, expect } from '@playwright/test'; +import fs from 'fs'; + +// Setup: Create screenshots directory if it doesn't exist +const screenshotDir = 'screenshots'; +fs.mkdirSync(screenshotDir, { recursive: true }); + +/** + * Test Case: Create Zones After Moving Canvas + */ +test('Create zones after moving canvas', async ({ page }) => { + // 1. Navigate to the application, log in, and set up + await loginAndSetup(page); + + // 2. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 3. Move the canvas to the top position + await moveCanvas(page); + + // 4. Select the zone tool + console.log('Selecting zone tool...'); + await page.getByTitle('Zone').getByRole('img').click(); + + // Define zone paths (start and end points) + const zonePaths = [ + { start: { x: 172, y: 215 }, end: { x: 292, y: 339 } }, + { start: { x: 328, y: 217 }, end: { x: 441, y: 340 } }, + { start: { x: 470, y: 220 }, end: { x: 593, y: 342 } }, + { start: { x: 174, y: 379 }, end: { x: 289, y: 517 } }, + { start: { x: 327, y: 378 }, end: { x: 442, y: 519 } }, + { start: { x: 468, y: 376 }, end: { x: 593, y: 521 } }, + { start: { x: 699, y: 197 }, end: { x: 801, y: 359 } }, + { start: { x: 913, y: 516 }, end: { x: 1040, y: 644 } }, + { start: { x: 1079, y: 518 }, end: { x: 1205, y: 647 } }, + { start: { x: 912, y: 355 }, end: { x: 1036, y: 473 } }, + { start: { x: 1082, y: 357 }, end: { x: 1203, y: 476 } }, + { start: { x: 916, y: 190 }, end: { x: 1193, y: 333 } }, + ]; + + // Create zones using reusable function + await createZones(page, zonePaths); + + // Take a final screenshot after creating zones + const zonesAfterPath = `${screenshotDir}/zones-created-after-moving-canvas.png`; + await page.screenshot({ path: zonesAfterPath }); + console.log(`Final screenshot saved at: ${zonesAfterPath}`); +}); + +/** + * Test Case: Delete Zones After Moving Canvas + */ +test('Delete zones after moving canvas', async ({ page }) => { + // 1. Navigate to the application, log in, and set up + await loginAndSetup(page); + + // 2. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 3. Move the canvas to the top position + await moveCanvas(page); + + // Open the "3 dots" menu and select the delete tool + console.log('Opening three-dot menu...'); + await page.locator('.drop-down-option-button > svg').click(); + console.log('Selecting Delete option...'); + await page.locator('div').filter({ hasText: /^Delete$/ }).first().click(); + + // Wait for the delete tool to be active + await page.waitForTimeout(1000); // Adjust timeout if necessary + + // Define zone paths (same as creation) + const zonePaths = [ + { start: { x: 172, y: 215 }, end: { x: 292, y: 339 } }, + { start: { x: 328, y: 217 }, end: { x: 441, y: 340 } }, + { start: { x: 470, y: 220 }, end: { x: 593, y: 342 } }, + { start: { x: 174, y: 379 }, end: { x: 289, y: 517 } }, + { start: { x: 327, y: 378 }, end: { x: 442, y: 519 } }, + { start: { x: 468, y: 376 }, end: { x: 593, y: 521 } }, + { start: { x: 699, y: 197 }, end: { x: 801, y: 359 } }, + { start: { x: 913, y: 516 }, end: { x: 1040, y: 644 } }, + { start: { x: 1079, y: 518 }, end: { x: 1205, y: 647 } }, + { start: { x: 912, y: 355 }, end: { x: 1036, y: 473 } }, + { start: { x: 1082, y: 357 }, end: { x: 1203, y: 476 } }, + { start: { x: 916, y: 190 }, end: { x: 1193, y: 333 } }, + ]; + + // Delete zones using reusable function + await deleteZones(page, zonePaths); + + // Take a final screenshot after deleting zones + const afterPath = `${screenshotDir}/zones-deleted-after-moving-canvas.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +/** + * Reusable function for creating zones. + * @param {Object} page - Playwright page object + * @param {Array} zonePaths - Array of {start, end} objects representing zone points + */ +async function createZones(page, zonePaths) { + console.log('Creating zones...'); + for (const { start, end } of zonePaths) { + console.log(`Creating zone from (${start.x}, ${start.y}) to (${end.x}, ${end.y})`); + await simulatePointerClick(page, start.x, start.y); // First click (start point) + await simulatePointerClick(page, end.x, end.y); // Second click (end point) + await page.waitForTimeout(200); // Add delay between actions + } +} + +/** + * Reusable function for deleting zones. + * @param {Object} page - Playwright page object + * @param {Array} zonePaths - Array of {start, end} objects representing zone points + */ +async function deleteZones(page, zonePaths) { + console.log('Deleting zones...'); + for (const { start, end } of zonePaths) { + console.log(`Deleting zone from (${start.x}, ${start.y}) to (${end.x}, ${end.y})`); + await simulatePointerClick(page, start.x, start.y); // Click at start point + await simulatePointerClick(page, end.x, end.y); // Click at end point + await page.waitForTimeout(200); // Add delay between actions + } +} + +/** + * Simulates a pointer click at specific coordinates. + */ +async function simulatePointerClick(page, x, y, button = 'left') { + // Move to the desired position + await page.mouse.move(x, y); + + // Simulate mouse down and up to mimic a real click + await page.mouse.down({ button }); + await page.mouse.up({ button }); +} + +/** + * Common setup function for logging in and switching to full-screen mode. + */ +async function loginAndSetup(page) { + // Navigate to the application + await page.goto('http://185.100.212.76:8200'); + + // Log in + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode +} + +/** + * Common function to move the canvas. + */ +async function moveCanvas(page) { + console.log('Moving canvas to the top position...'); + const canvas = page.locator('canvas').first(); + const canvasBox = await canvas.boundingBox(); + + if (!canvasBox) { + throw new Error('Canvas bounding box not found. Ensure the canvas is visible.'); + } + + // Start position (center of canvas) + const startX = canvasBox.x + canvasBox.width / 2; + const startY = canvasBox.y + canvasBox.height / 2; + + // Simulate a drag action to move the canvas + await page.mouse.move(startX, startY); + await page.mouse.down(); + + // Move the mouse down while dragging + await page.mouse.move(startX, startY + 100, { + steps: 20, // Smooth movement + }); + + // Simultaneously scroll the page (if needed) + await page.mouse.wheel(0, 500); // Scroll down 500px + + await page.mouse.up(); +} \ No newline at end of file diff --git a/tests/login.spec.js b/tests/login.spec.js index 472e378..57b3a16 100644 --- a/tests/login.spec.js +++ b/tests/login.spec.js @@ -10,4 +10,59 @@ test('Login page', async ({ page }) => { await page.getByRole('button', { name: 'Continue', exact: true }).click(); await page.waitForTimeout(3000); +}); +import { test, expect } from '@playwright/test'; +import fs from 'fs'; + +test('Draw walls on canvas using precise coordinates', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // Login + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // Switch to 2D mode and select wall tool + await page.locator('.toggle-option:has-text("2d")').click(); + await page.getByTitle('Wall').getByRole('img').click(); + + // Take before screenshot + await page.screenshot({ path: `${screenshotDir}/before.png` }); + + // Draw wall using your exact coordinates + const canvas = page.locator('canvas'); + + // First wall segment + await canvas.click({ position: { x: 74, y: 111 } }); + await canvas.click({ position: { x: 733, y: 100 } }); + + // Second wall segment + await canvas.click({ position: { x: 733, y: 594 } }); + + // Third wall segment + await canvas.click({ position: { x: 60, y: 593 } }); + + // Fourth wall segment (closing the wall) + await canvas.click({ position: { x: 74, y: 107 } }); + + // Finalize with right-click + await canvas.click({ + button: 'right', + position: { x: 23, y: 129 } + }); + + // Take after screenshot + const afterPath = `${screenshotDir}/after.png`; + await page.screenshot({ path: afterPath }); + + // Verification + const canvasData = await canvas.evaluate(el => el.toDataURL()); + expect(canvasData).not.toBe(''); // Canvas should have content + + const beforeImg = fs.readFileSync(`${screenshotDir}/before.png`); + const afterImg = fs.readFileSync(afterPath); + expect(beforeImg.equals(afterImg)).toBe(false); // Screenshots should differ }); \ No newline at end of file diff --git a/tests/safety.spec.js b/tests/safety.spec.js new file mode 100644 index 0000000..e39cf6e --- /dev/null +++ b/tests/safety.spec.js @@ -0,0 +1,405 @@ +import { test, expect } from '@playwright/test'; +import fs from 'fs'; + +test('Create walls using reusable function', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode and select wall tool + await page.locator('.toggle-option:has-text("2d")').click(); + await page.getByTitle('Wall').getByRole('img').click(); + + // 4. Wait for the canvas to be ready + const canvas = page.locator('canvas'); + await canvas.waitFor(); + + // 5. Draw walls using reusable function + const wallCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + await drawOrDeleteWalls(page, wallCoordinates, 'create'); + + // 6. Take a final screenshot after drawing walls + const afterPath = `${screenshotDir}/walls-created-fullscreen.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +test('Delete walls and 3 dots menu using reusable function', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 4. Select the delete tool + console.log('Opening three-dot menu...'); + await page.locator('.drop-down-option-button > svg').click(); + + console.log('Selecting Delete option...'); + await page.locator('div').filter({ hasText: /^Delete$/ }).first().click(); + + // 5. Wait for the canvas to be ready + const canvas = page.locator('canvas'); + await canvas.waitFor(); + + // 6. Delete walls using reusable function + const wallCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 146, y: 343 }, + { x: 328, y: 542 }, + { x: 618, y: 459 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + await drawOrDeleteWalls(page, wallCoordinates, 'delete'); + + // 7. Delete the "3 dots" menu if it's part of the canvas + console.log('Deleting the 3 dots menu...'); + try { + // Attempt to locate and click the "3 dots" menu + const threeDotsMenu = page.locator('.drop-down-option-button > svg'); + await threeDotsMenu.waitFor({ state: 'visible', timeout: 5000 }); // Ensure it's visible + await threeDotsMenu.click(); // Click to select it + await simulatePointerClick(page, 500, 500); // Simulate a delete action on the canvas + + console.log('Successfully deleted the 3 dots menu.'); + } catch (error) { + console.error('Failed to delete the 3 dots menu:', error.message); + } + + // 8. Take a final screenshot after deleting walls and the 3 dots menu + const afterPath = `${screenshotDir}/walls-deleted-fullscreen.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +/** + * Simulates a pointer click at specific coordinates. + */ +async function simulatePointerClick(page, x, y, button = 'left') { + // Move to the desired position + await page.mouse.move(x, y); + + // Simulate mouse down and up to mimic a real click + await page.mouse.down({ button }); + await page.mouse.up({ button }); +} + +/** + * Reusable function for creating or deleting walls. + * @param {Object} page - Playwright page object + * @param {Array} coordinates - Array of {x, y} objects representing wall points + * @param {String} action - 'create' or 'delete' + */ +async function drawOrDeleteWalls(page, coordinates, action) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} walls...`); + + for (const { x, y } of coordinates) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} at (${x}, ${y})`); + await simulatePointerClick(page, x, y); + } + + if (action === 'create') { + // Finalize wall creation with right-click + await simulatePointerClick(page, 100, 160, 'right'); // Right-click to finalize + } +} + +//Secound config +import { test, expect } from '@playwright/test'; +import fs from 'fs'; + +test('Create walls after moving canvas', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 4. Move the canvas to the top position + console.log('Moving canvas to the top position...'); + const canvas = page.locator('canvas').first(); + const canvasBox = await canvas.boundingBox(); + + if (!canvasBox) { + throw new Error('Canvas bounding box not found. Ensure the canvas is visible.'); + } + + // Start position (center of canvas) + const startX = canvasBox.x + canvasBox.width / 2; + const startY = canvasBox.y + canvasBox.height / 2; + + // Simulate a drag action to move the canvas + await page.mouse.move(startX, startY); + await page.mouse.down(); + + // Move the mouse down while dragging + await page.mouse.move(startX, startY + 100, { + steps: 20, // Smooth movement + }); + + // Simultaneously scroll the page (if needed) + await page.mouse.wheel(0, 500); // Scroll down 500px + + await page.mouse.up(); + + // 5. Select the wall tool + console.log('Selecting wall tool...'); + await page.getByTitle('Wall').getByRole('img').click(); + + // 6. Draw walls using reusable function + const wallCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + await drawOrDeleteWalls(page, wallCoordinates, 'create'); + + // 7. Take a final screenshot after drawing walls + const afterPath = `${screenshotDir}/walls-created-after-moving-canvas.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +test('Delete walls after moving canvas', async ({ page }) => { + // Setup + const screenshotDir = 'screenshots'; + fs.mkdirSync(screenshotDir, { recursive: true }); + + // 1. Navigate to the application + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // 2. Switch to full-screen mode + console.log('Switching to full-screen mode...'); + await page.keyboard.press('F11'); // Simulate pressing F11 to enter full-screen mode + + // 3. Switch to 2D mode + await page.locator('.toggle-option:has-text("2d")').click(); + + // 4. Move the canvas to the top position + console.log('Moving canvas to the top position...'); + const canvas = page.locator('canvas').first(); + const canvasBox = await canvas.boundingBox(); + + if (!canvasBox) { + throw new Error('Canvas bounding box not found. Ensure the canvas is visible.'); + } + + // Start position (center of canvas) + const startX = canvasBox.x + canvasBox.width / 2; + const startY = canvasBox.y + canvasBox.height / 2; + + // Simulate a drag action to move the canvas + await page.mouse.move(startX, startY); + await page.mouse.down(); + + // Move the mouse down while dragging + await page.mouse.move(startX, startY + 100, { + steps: 20, // Smooth movement + }); + + // Simultaneously scroll the page (if needed) + await page.mouse.wheel(0, 500); // Scroll down 500px + + await page.mouse.up(); + + // 5. Open the "3 dots" menu and select the delete tool + console.log('Opening three-dot menu...'); + await page.locator('.drop-down-option-button > svg').click(); + + console.log('Selecting Delete option...'); + await page.locator('div').filter({ hasText: /^Delete$/ }).first().click(); + + // Wait for the delete tool to be active + await page.waitForTimeout(1000); // Adjust timeout if necessary + + // 6. Define specific points for deletion + const deleteCoordinates = [ + { x: 147, y: 212 }, + { x: 138, y: 542 }, + { x: 619, y: 548 }, + { x: 614, y: 286 }, + { x: 693, y: 284 }, + { x: 696, y: 374 }, + { x: 820, y: 369 }, + { x: 823, y: 285 }, + { x: 889, y: 285 }, + { x: 899, y: 662 }, + { x: 1249, y: 661 }, + { x: 1238, y: 122 }, + { x: 142, y: 116 }, + { x: 53, y: 124 }, + { x: 147, y: 212 }, + ]; + + // Delete walls using enhanced deletion function + await enhancedDeleteWalls(page, deleteCoordinates); + + // 7. Take a final screenshot after deleting walls + const afterPath = `${screenshotDir}/walls-deleted-after-moving-canvas.png`; + await page.screenshot({ path: afterPath }); + console.log(`Final screenshot saved at: ${afterPath}`); +}); + +/** + * Reusable function for creating or deleting walls. + * @param {Object} page - Playwright page object + * @param {Array} coordinates - Array of {x, y} objects representing wall points + * @param {String} action - 'create' or 'delete' + */ +async function drawOrDeleteWalls(page, coordinates, action) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} walls...`); + + for (const { x, y } of coordinates) { + console.log(`${action === 'create' ? 'Creating' : 'Deleting'} at (${x}, ${y})`); + await simulatePointerClick(page, x, y); + + // Add a small delay between clicks to ensure proper interaction + await page.waitForTimeout(300); // Adjust timeout if necessary + } + + if (action === 'create') { + // Finalize wall creation with right-click + await simulatePointerClick(page, 100, 160, 'right'); // Right-click to finalize + } +} + +/** + * Simulates a pointer click at specific coordinates. + */ +async function simulatePointerClick(page, x, y, button = 'left') { + // Move to the desired position + await page.mouse.move(x, y); + + // Simulate mouse down and up to mimic a real click + await page.mouse.down({ button }); + await page.mouse.up({ button }); +} + +/** + * Enhanced deletion function with retries, expanded click area, and success check. + * @param {Object} page - Playwright page object + * @param {Array} coordinates - Array of {x, y} objects representing wall points + */ +async function enhancedDeleteWalls(page, coordinates) { + console.log('Enhanced deletion process started...'); + + for (const { x, y } of coordinates) { + let isDeleted = false; + const maxRetries = 2; // Reduced maximum number of retries + let retryCount = 0; + + // Attempt deletion with retries + while (!isDeleted && retryCount < maxRetries) { + console.log(`Attempting to delete at (${x}, ${y}), attempt ${retryCount + 1}`); + + // Expand the click area slightly to account for imprecise targeting + const offsets = [ + { dx: 0, dy: 0 }, // Exact coordinate + { dx: 5, dy: 0 }, // Slightly to the right + { dx: -5, dy: 0 }, // Slightly to the left + { dx: 0, dy: 5 }, // Slightly below + { dx: 0, dy: -5 }, // Slightly above + ]; + + for (const { dx, dy } of offsets) { + const adjustedX = x + dx; + const adjustedY = y + dy; + + console.log(`Clicking at adjusted position (${adjustedX}, ${adjustedY})`); + await simulatePointerClick(page, adjustedX, adjustedY); + + // Add a small delay between clicks to ensure proper interaction + await page.waitForTimeout(100); // Reduced delay + + // Check if the wall is deleted (custom logic can be added here if possible) + // For now, assume success after trying all offsets + isDeleted = true; // Placeholder for actual deletion check + } + + retryCount++; + } + + if (!isDeleted) { + console.warn(`Failed to delete wall at (${x}, ${y}) after ${maxRetries} attempts.`); + } + } +} \ No newline at end of file diff --git a/tests/screenshot.spec.js b/tests/screenshot.spec.js index 5c7feda..81cb7b0 100644 --- a/tests/screenshot.spec.js +++ b/tests/screenshot.spec.js @@ -28,99 +28,91 @@ async function takeScreenshotsAtViewports(page, folderName, screenshotPrefix) { } } -// test('Login Page Screenshots', async ({ page }) => { -// test.setTimeout(60000); // Increase timeout to 60 seconds -// const url = 'http://185.100.212.76:8200'; -// const folderName = 'login-screenshots'; +test('Login Page Screenshots', async ({ page }) => { + test.setTimeout(60000); // Increase timeout to 60 seconds + const url = 'http://185.100.212.76:8200'; + const folderName = 'login-screenshots'; -// try { -// console.log('Navigating to the login page...'); -// await page.goto(url, { waitUntil: 'networkidle' }); -// await page.waitForSelector('[placeholder="Email"]', { timeout: 10000 }); -// await takeScreenshotsAtViewports(page, `${folderName}/login-page-loaded`, 'login-page-loaded'); + try { + console.log('Navigating to the login page...'); + await page.goto(url, { waitUntil: 'networkidle' }); + await page.waitForSelector('[placeholder="Email"]', { timeout: 10000 }); + await takeScreenshotsAtViewports(page, `${folderName}/login-page-loaded`, 'login-page-loaded'); -// console.log('Filling Email and Password fields...'); -// await page.getByPlaceholder('Email').click(); -// await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); -// await page.getByPlaceholder('Password').click(); -// await page.getByPlaceholder('Password').fill('123456'); -// await takeScreenshotsAtViewports(page, `${folderName}/fields-filled`, 'fields-filled'); + console.log('Filling Email and Password fields...'); + await page.getByPlaceholder('Email').click(); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').click(); + await page.getByPlaceholder('Password').fill('123456'); + await takeScreenshotsAtViewports(page, `${folderName}/fields-filled`, 'fields-filled'); -// console.log('Clicking the Continue button...'); -// await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); -// await page.getByRole('button', { name: 'Continue', exact: true }).click(); -// await page.waitForLoadState('networkidle'); // Wait for navigation or animations to complete -// await takeScreenshotsAtViewports(page, `${folderName}/after-login`, 'after-login'); -// } catch (error) { -// console.error('An error occurred during the test:', error.message); -// throw error; // Re-throw the error to fail the test -// } -// }); + console.log('Clicking the Continue button...'); + await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.waitForLoadState('networkidle'); // Wait for navigation or animations to complete + await takeScreenshotsAtViewports(page, `${folderName}/after-login`, 'after-login'); + } catch (error) { + console.error('An error occurred during the test:', error.message); + throw error; // Re-throw the error to fail the test + } +}); -// test('simulation Page Screenshots', async ({ page }) => {{ +test('simulation Page Screenshots', async ({ page }) => {{ -// const folderName = 'simulation-screenshots'; + const folderName = 'simulation-screenshots'; -// await page.goto('http://185.100.212.76:8200'); -// await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); -// await page.getByPlaceholder('Password').fill('123456'); -// await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); -// await page.getByRole('button', { name: 'Continue', exact: true }).click(); -// await page.getByText('Simulation').click(); -// await page.waitForTimeout(4000); -// await takeScreenshotsAtViewports(page, `${folderName}/simulation-page-loaded`, 'simulation-page-loaded'); + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.waitForTimeout(10000); // Wait for the page to load + await page.getByText('Simulation').click(); + await page.waitForTimeout(4000); + await takeScreenshotsAtViewports(page, `${folderName}/simulation-page-loaded`, 'simulation-page-loaded'); -// } -// }); +} +}); -// test('Visualization Page Screenshots', async ({ page }) => { -// const folderName = 'Visualization-screenshots'; - -// // Navigate to the login page and log in -// await page.goto('http://185.100.212.76:8200'); -// await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); -// await page.getByPlaceholder('Password').fill('123456'); -// await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); -// await page.getByRole('button', { name: 'Continue', exact: true }).click(); - -// // Navigate to the Visualization page -// await page.getByText('Visualization').click(); -// await page.waitForTimeout(4000); // Wait for the page to load -// await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page1-loaded`, 'Visualization1-page-loaded'); - -// // Navigate to Templates and Design pages -// await page.locator('.toggle-header-item:has-text("Templates")').click(); // Use a more specific selector -// await page.getByText('Design').click(); // Ensure this is unique -// await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page2-loaded`, 'Visualization2-page-loaded'); -// }); - -// test('Market-Place Page Screenshots', async ({ page }) => {{ - -// const folderName = 'simulation-screenshots'; - -// await page.goto('http://185.100.212.76:8200'); -// await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); -// await page.getByPlaceholder('Password').fill('123456'); -// await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); -// await page.getByRole('button', { name: 'Continue', exact: true }).click(); -// await page.getByText('Market Place').click(); -// await page.waitForTimeout(4000); -// await takeScreenshotsAtViewports(page, `${folderName}/Market-Place-page-loaded`, 'Market-Place-page-loaded'); - -// } -// }); - -test('Visualization-Drag&Drop Page Screenshots', async ({ page }) => { +test('Visualization Page Screenshots', async ({ page }) => { const folderName = 'Visualization-screenshots'; // Navigate to the login page and log in await page.goto('http://185.100.212.76:8200'); - await page.getByPlaceholder('Email').fill('nalvazhuthi@hexrfactory.com'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); await page.getByPlaceholder('Password').fill('123456'); await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); await page.getByRole('button', { name: 'Continue', exact: true }).click(); + + // Navigate to the Visualization page + await page.waitForTimeout(10000); // Wait for the page to load await page.getByText('Visualization').click(); - // await page.waitForTimeout(4000); - await page.getByTitle('Activate left panel').click(); - await page.waitForTimeout(4000); + await page.waitForTimeout(4000); // Wait for the page to load + await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page1-loaded`, 'Visualization1-page-loaded'); + + await page.locator('.toggle-header-item:has-text("3D")').click(); // Use a more specific selector + await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page1-loaded`, 'Visualization1-page-loaded-3D'); + + await page.locator('.toggle-header-item:has-text("Floating")').click(); // Use a more specific selector + await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page1-loaded`, 'Visualization1-page-loaded-Floating'); + // Navigate to Templates and Design pages + await page.locator('.toggle-header-item:has-text("Templates")').click(); // Use a more specific selector + await takeScreenshotsAtViewports(page, `${folderName}/Visualization-page2-loaded`, 'Visualization2-page-loaded'); +}); + +test('Market-Place Page Screenshots', async ({ page }) => {{ + + const folderName = 'simulation-screenshots'; + + await page.goto('http://185.100.212.76:8200'); + await page.getByPlaceholder('Email').fill('ramkumar@tester.local'); + await page.getByPlaceholder('Password').fill('123456'); + await page.waitForSelector('button:has-text("Continue")', { timeout: 10000 }); + await page.getByRole('button', { name: 'Continue', exact: true }).click(); + await page.waitForTimeout(10000); // Wait for the page to load + await page.getByText('Market Place').click(); + await page.waitForTimeout(4000); + await takeScreenshotsAtViewports(page, `${folderName}/Market-Place-page-loaded`, 'Market-Place-page-loaded'); + +} });