From 571d0bfb75e4d79a0e23c50073ff14d40c0a7396 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:03:36 +0200 Subject: [PATCH 01/78] Initialized playwright --- .github/workflows/playwright.yml | 27 ++ .gitignore | 4 + e2e/example.spec.js | 19 ++ package-lock.json | 107 ++++++- package.json | 2 + playwright.config.js | 79 +++++ tests-examples/demo-todo-app.spec.js | 449 +++++++++++++++++++++++++++ 7 files changed, 681 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/playwright.yml create mode 100644 e2e/example.spec.js create mode 100644 playwright.config.js create mode 100644 tests-examples/demo-todo-app.spec.js diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..467190be6 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index d6a78b9b8..ded603bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ firebase-debug.log *.njsproj *.sln *.sw? +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/e2e/example.spec.js b/e2e/example.spec.js new file mode 100644 index 000000000..40eddb861 --- /dev/null +++ b/e2e/example.spec.js @@ -0,0 +1,19 @@ +// @ts-check +const { test, expect } = require('@playwright/test'); + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); +}); diff --git a/package-lock.json b/package-lock.json index 9e0832223..2187cdac3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,10 +40,12 @@ }, "devDependencies": { "@intlify/vue-i18n-loader": "^1.1.0", + "@playwright/test": "^1.44.1", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "12", "@testing-library/vue": "^5.9.0", + "@types/node": "^20.12.12", "@vue/cli-plugin-babel": "~4.3.0", "@vue/cli-plugin-eslint": "~4.3.0", "@vue/cli-plugin-router": "~4.3.0", @@ -4582,6 +4584,21 @@ "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", "dev": true }, + "node_modules/@playwright/test": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "dev": true, + "dependencies": { + "playwright": "1.44.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "license": "BSD-3-Clause" @@ -5208,9 +5225,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", - "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dependencies": { "undici-types": "~5.26.4" } @@ -20104,6 +20121,50 @@ "node": ">=4" } }, + "node_modules/playwright": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "dev": true, + "dependencies": { + "playwright-core": "1.44.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -30333,6 +30394,15 @@ "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", "dev": true }, + "@playwright/test": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "dev": true, + "requires": { + "playwright": "1.44.1" + } + }, "@protobufjs/aspromise": { "version": "1.1.2" }, @@ -30834,9 +30904,9 @@ "version": "3.0.3" }, "@types/node": { - "version": "20.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", - "integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "requires": { "undici-types": "~5.26.4" } @@ -41806,6 +41876,31 @@ "find-up": "^2.1.0" } }, + "playwright": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.44.1" + }, + "dependencies": { + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + } + } + }, + "playwright-core": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "dev": true + }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", diff --git a/package.json b/package.json index 30c3dcd2c..6ec7ca973 100644 --- a/package.json +++ b/package.json @@ -47,10 +47,12 @@ }, "devDependencies": { "@intlify/vue-i18n-loader": "^1.1.0", + "@playwright/test": "^1.44.1", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "12", "@testing-library/vue": "^5.9.0", + "@types/node": "^20.12.12", "@vue/cli-plugin-babel": "~4.3.0", "@vue/cli-plugin-eslint": "~4.3.0", "@vue/cli-plugin-router": "~4.3.0", diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 000000000..132835e59 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,79 @@ +// @ts-check +const { defineConfig, devices } = require('@playwright/test'); + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * @see https://playwright.dev/docs/test-configuration + */ +module.exports = defineConfig({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); + diff --git a/tests-examples/demo-todo-app.spec.js b/tests-examples/demo-todo-app.spec.js new file mode 100644 index 000000000..e2eb87ce1 --- /dev/null +++ b/tests-examples/demo-todo-app.spec.js @@ -0,0 +1,449 @@ +// @ts-check +const { test, expect } = require('@playwright/test'); + +test.beforeEach(async ({ page }) => { + await page.goto('https://demo.playwright.dev/todomvc'); +}); + +const TODO_ITEMS = [ + 'buy some cheese', + 'feed the cat', + 'book a doctors appointment' +]; + +test.describe('New Todo', () => { + test('should allow me to add todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create 1st todo. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Make sure the list only has one todo item. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0] + ]); + + // Create 2nd todo. + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + + // Make sure the list now has two todo items. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[1] + ]); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); + + test('should clear text input field when an item is added', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create one todo item. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Check that input is empty. + await expect(newTodo).toBeEmpty(); + await checkNumberOfTodosInLocalStorage(page, 1); + }); + + test('should append new items to the bottom of the list', async ({ page }) => { + // Create 3 items. + await createDefaultTodos(page); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + // Check test using different methods. + await expect(page.getByText('3 items left')).toBeVisible(); + await expect(todoCount).toHaveText('3 items left'); + await expect(todoCount).toContainText('3'); + await expect(todoCount).toHaveText(/3/); + + // Check all items in one call. + await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); + await checkNumberOfTodosInLocalStorage(page, 3); + }); +}); + +test.describe('Mark all as completed', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test.afterEach(async ({ page }) => { + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should allow me to mark all items as completed', async ({ page }) => { + // Complete all todos. + await page.getByLabel('Mark all as complete').check(); + + // Ensure all todos have 'completed' class. + await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + }); + + test('should allow me to clear the complete state of all items', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + // Check and then immediately uncheck. + await toggleAll.check(); + await toggleAll.uncheck(); + + // Should be no completed classes. + await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); + }); + + test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + await toggleAll.check(); + await expect(toggleAll).toBeChecked(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Uncheck first todo. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').uncheck(); + + // Reuse toggleAll locator and make sure its not checked. + await expect(toggleAll).not.toBeChecked(); + + await firstTodo.getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Assert the toggle all is checked again. + await expect(toggleAll).toBeChecked(); + }); +}); + +test.describe('Item', () => { + + test('should allow me to mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + // Check first item. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').check(); + await expect(firstTodo).toHaveClass('completed'); + + // Check second item. + const secondTodo = page.getByTestId('todo-item').nth(1); + await expect(secondTodo).not.toHaveClass('completed'); + await secondTodo.getByRole('checkbox').check(); + + // Assert completed class. + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).toHaveClass('completed'); + }); + + test('should allow me to un-mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const firstTodo = page.getByTestId('todo-item').nth(0); + const secondTodo = page.getByTestId('todo-item').nth(1); + const firstTodoCheckbox = firstTodo.getByRole('checkbox'); + + await firstTodoCheckbox.check(); + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await firstTodoCheckbox.uncheck(); + await expect(firstTodo).not.toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 0); + }); + + test('should allow me to edit an item', async ({ page }) => { + await createDefaultTodos(page); + + const todoItems = page.getByTestId('todo-item'); + const secondTodo = todoItems.nth(1); + await secondTodo.dblclick(); + await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); + await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); + + // Explicitly assert the new text value. + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2] + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); +}); + +test.describe('Editing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should hide other controls when editing', async ({ page }) => { + const todoItem = page.getByTestId('todo-item').nth(1); + await todoItem.dblclick(); + await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); + await expect(todoItem.locator('label', { + hasText: TODO_ITEMS[1], + })).not.toBeVisible(); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should save edits on blur', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should trim entered text', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should remove the item if an empty text string was entered', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[2], + ]); + }); + + test('should cancel edits on escape', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); + await expect(todoItems).toHaveText(TODO_ITEMS); + }); +}); + +test.describe('Counter', () => { + test('should display the current number of todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + await expect(todoCount).toContainText('1'); + + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + await expect(todoCount).toContainText('2'); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); +}); + +test.describe('Clear completed button', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + }); + + test('should display the correct text', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); + }); + + test('should remove completed items when clicked', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).getByRole('checkbox').check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(todoItems).toHaveCount(2); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should be hidden when there are no items that are completed', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); + }); +}); + +test.describe('Persistence', () => { + test('should persist its data', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const todoItems = page.getByTestId('todo-item'); + const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); + await firstTodoCheck.check(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + + // Ensure there is 1 completed item. + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + // Now reload. + await page.reload(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + }); +}); + +test.describe('Routing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + // make sure the app had a chance to save updated todos in storage + // before navigating to a new view, otherwise the items can get lost :( + // in some frameworks like Durandal + await checkTodosInLocalStorage(page, TODO_ITEMS[0]); + }); + + test('should allow me to display active items', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await expect(todoItem).toHaveCount(2); + await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should respect the back button', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await test.step('Showing all items', async () => { + await page.getByRole('link', { name: 'All' }).click(); + await expect(todoItem).toHaveCount(3); + }); + + await test.step('Showing active items', async () => { + await page.getByRole('link', { name: 'Active' }).click(); + }); + + await test.step('Showing completed items', async () => { + await page.getByRole('link', { name: 'Completed' }).click(); + }); + + await expect(todoItem).toHaveCount(1); + await page.goBack(); + await expect(todoItem).toHaveCount(2); + await page.goBack(); + await expect(todoItem).toHaveCount(3); + }); + + test('should allow me to display completed items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Completed' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(1); + }); + + test('should allow me to display all items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await page.getByRole('link', { name: 'Completed' }).click(); + await page.getByRole('link', { name: 'All' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(3); + }); + + test('should highlight the currently applied filter', async ({ page }) => { + await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); + + //create locators for active and completed links + const activeLink = page.getByRole('link', { name: 'Active' }); + const completedLink = page.getByRole('link', { name: 'Completed' }); + await activeLink.click(); + + // Page change - active items. + await expect(activeLink).toHaveClass('selected'); + await completedLink.click(); + + // Page change - completed items. + await expect(completedLink).toHaveClass('selected'); + }); +}); + +async function createDefaultTodos(page) { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } +} + +/** + * @param {import('@playwright/test').Page} page + * @param {number} expected + */ + async function checkNumberOfTodosInLocalStorage(page, expected) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).length === e; + }, expected); +} + +/** + * @param {import('@playwright/test').Page} page + * @param {number} expected + */ + async function checkNumberOfCompletedTodosInLocalStorage(page, expected) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).filter(i => i.completed).length === e; + }, expected); +} + +/** + * @param {import('@playwright/test').Page} page + * @param {string} title + */ +async function checkTodosInLocalStorage(page, title) { + return await page.waitForFunction(t => { + return JSON.parse(localStorage['react-todos']).map(i => i.title).includes(t); + }, title); +} From 5a31b1070cb0520a6652d79859700a0731ba7a21 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:05:21 +0200 Subject: [PATCH 02/78] Configured playwright --- playwright.config.js | 57 ++++++++++---------------------------------- 1 file changed, 13 insertions(+), 44 deletions(-) diff --git a/playwright.config.js b/playwright.config.js index 132835e59..a7e77f982 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,34 +1,31 @@ // @ts-check -const { defineConfig, devices } = require('@playwright/test'); +const { defineConfig, devices } = require('@playwright/test') -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - -/** - * @see https://playwright.dev/docs/test-configuration - */ module.exports = defineConfig({ testDir: './e2e', /* Run tests in files in parallel */ fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, + /* Retry on CI only */ retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + /* Output directory for screenshots of failed tests */ + outputDir: './playwright/output', + use: { + /* Collect trace when retrying the failed test */ trace: 'on-first-retry', + + /* Create a screenshot if a test fails */ + screenshot: { mode: 'only-on-failure', fullPage: true }, }, /* Configure projects for major browsers */ @@ -47,33 +44,5 @@ module.exports = defineConfig({ name: 'webkit', use: { ...devices['Desktop Safari'] }, }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, ], - - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:3000', - // reuseExistingServer: !process.env.CI, - // }, -}); - +}) From c6252316f620f4456cae0ea587c0d9907352c34c Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:09:45 +0200 Subject: [PATCH 03/78] Added the test file --- e2e/example.spec.js | 19 ------- e2e/ruxailabtest.spec.js | 108 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 19 deletions(-) delete mode 100644 e2e/example.spec.js create mode 100644 e2e/ruxailabtest.spec.js diff --git a/e2e/example.spec.js b/e2e/example.spec.js deleted file mode 100644 index 40eddb861..000000000 --- a/e2e/example.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); - -test('has title', async ({ page }) => { - await page.goto('https://playwright.dev/'); - - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/Playwright/); -}); - -test('get started link', async ({ page }) => { - await page.goto('https://playwright.dev/'); - - // Click the get started link. - await page.getByRole('link', { name: 'Get started' }).click(); - - // Expects page to have a heading with the name of Installation. - await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible(); -}); diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js new file mode 100644 index 000000000..89e8c76f7 --- /dev/null +++ b/e2e/ruxailabtest.spec.js @@ -0,0 +1,108 @@ +const { test, expect } = require('@playwright/test') + +test('has link page', async ({ page }) => { + await page.goto('https://ruxailab-prod.web.app/') + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/RUXAILAB/) +}) + +test('sign and create heurisic test', async ({ page }) => { + await page.goto('https://ruxailab-prod.web.app/signin') + await page + .getByRole('textbox', { name: 'E-mail' }) + .fill('testemail@gmail.com') + await page.getByRole('textbox', { name: 'Password' }).fill('password123') + await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + await page.waitForTimeout(2000) // 2 segundo de delay + await page.click('.card-title:has-text("Create a blank test")') + + await page.click('.card.col-sm-10.col-md-5.col-10') + await page + .getByRole('textbox', { name: 'Test Name' }) + .fill('Test heuristic playwright') + await page + .getByRole('textbox', { name: 'Test Description' }) + .fill('Some descripton') + + await page.click( + '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', + ) + // back console + await page.waitForTimeout(2000) // 2 segundo de delay + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) +}) + +test('sign and create usability test', async ({ page }) => { + /*login*/ + await page.goto('https://ruxailab-prod.web.app/signin') + await page.waitForTimeout(2000) // 2 segundo de delay + await page + .getByRole('textbox', { name: 'E-mail' }) + .fill('testemail@gmail.com') + await page.getByRole('textbox', { name: 'Password' }).fill('password123') + await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + await page.waitForTimeout(2000) // 2 segundo de delay + await page.click('.card-title:has-text("Create a blank test")') + await page.click('.card.col-sm-10.col-md-5.col-12') + await page + .getByRole('textbox', { name: 'Test Name' }) + .fill('Test usability playwright') + await page + .getByRole('textbox', { name: 'Test Description' }) + .fill('Some descripton') + + await page.click( + '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', + ) + // type test + await page.click('.card.col-sm-10.col-md-4.col-10') /*selfTEst */ + + // back console + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) +}) + +test('sign and create template', async ({ page }) => { + /*login*/ + await page.goto('https://ruxailab-prod.web.app/signin') + await page.waitForTimeout(2000) // 2 segundo de delay + await page + .getByRole('textbox', { name: 'E-mail' }) + .fill('testemail@gmail.com') + await page.getByRole('textbox', { name: 'Password' }).fill('password123') + await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + await page.waitForTimeout(2000) // 2 segundo de delay + await page.click('.card-title:has-text("Create from template")') + //create MARCTEST + await page.click('.v-list-item.v-list-item--link.theme--light') + await page.waitForTimeout(2000) // 2 segundo de delay + await page.getByRole('button', { name: 'NEXT' }).click() + await page + .getByRole('textbox', { name: 'Title' }) + .fill('Test template playwrigth') + await page + .getByRole('textbox', { name: 'Description' }) + .fill('Some description for template') + await page.waitForTimeout(2000) // 2 segundo de delay + await page.getByRole('button', { name: 'CREATE' }).click() + // back console + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) +}) From 3b4feb797aa48c72c110bda87a1968529b306c2d Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:17:38 +0200 Subject: [PATCH 04/78] Created a github action workflow file for playwright testing --- .github/workflows/playwright.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 467190be6..23b0f2fdb 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,9 +1,9 @@ name: Playwright Tests on: push: - branches: [ main, master ] + branches: [ develop, master, playwritght-testing ] pull_request: - branches: [ main, master ] + branches: [ develop, master, playwritght-testing ] jobs: test: timeout-minutes: 60 @@ -12,16 +12,22 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: lts/* + node-version: 18 - name: Install dependencies run: npm ci - name: Install Playwright Browsers run: npx playwright install --with-deps - name: Run Playwright tests - run: npx playwright test + run: npx playwright test - uses: actions/upload-artifact@v4 - if: always() + if: ${{ !cancelled() }} with: name: playwright-report path: playwright-report/ retention-days: 30 + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: playwright-screenshots + path: playwright/output + retention-days: 30 From a119d308c5a80ceccfe9a727434905a6fcfa0662 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:22:14 +0200 Subject: [PATCH 05/78] Changed the conditions for running playwright tests --- .github/workflows/playwright.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 23b0f2fdb..41abbf27d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,9 +1,7 @@ name: Playwright Tests -on: - push: - branches: [ develop, master, playwritght-testing ] - pull_request: - branches: [ develop, master, playwritght-testing ] + +on: [push, pull_request] + jobs: test: timeout-minutes: 60 From 98c9577a79c8b3376fad1d1bfc2f4cfffe523abd Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 16:29:37 +0200 Subject: [PATCH 06/78] Removed playwright example tests --- tests-examples/demo-todo-app.spec.js | 449 --------------------------- 1 file changed, 449 deletions(-) delete mode 100644 tests-examples/demo-todo-app.spec.js diff --git a/tests-examples/demo-todo-app.spec.js b/tests-examples/demo-todo-app.spec.js deleted file mode 100644 index e2eb87ce1..000000000 --- a/tests-examples/demo-todo-app.spec.js +++ /dev/null @@ -1,449 +0,0 @@ -// @ts-check -const { test, expect } = require('@playwright/test'); - -test.beforeEach(async ({ page }) => { - await page.goto('https://demo.playwright.dev/todomvc'); -}); - -const TODO_ITEMS = [ - 'buy some cheese', - 'feed the cat', - 'book a doctors appointment' -]; - -test.describe('New Todo', () => { - test('should allow me to add todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create 1st todo. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Make sure the list only has one todo item. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0] - ]); - - // Create 2nd todo. - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - - // Make sure the list now has two todo items. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[1] - ]); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); - - test('should clear text input field when an item is added', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create one todo item. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Check that input is empty. - await expect(newTodo).toBeEmpty(); - await checkNumberOfTodosInLocalStorage(page, 1); - }); - - test('should append new items to the bottom of the list', async ({ page }) => { - // Create 3 items. - await createDefaultTodos(page); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - // Check test using different methods. - await expect(page.getByText('3 items left')).toBeVisible(); - await expect(todoCount).toHaveText('3 items left'); - await expect(todoCount).toContainText('3'); - await expect(todoCount).toHaveText(/3/); - - // Check all items in one call. - await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); - await checkNumberOfTodosInLocalStorage(page, 3); - }); -}); - -test.describe('Mark all as completed', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test.afterEach(async ({ page }) => { - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should allow me to mark all items as completed', async ({ page }) => { - // Complete all todos. - await page.getByLabel('Mark all as complete').check(); - - // Ensure all todos have 'completed' class. - await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - }); - - test('should allow me to clear the complete state of all items', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - // Check and then immediately uncheck. - await toggleAll.check(); - await toggleAll.uncheck(); - - // Should be no completed classes. - await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); - }); - - test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - await toggleAll.check(); - await expect(toggleAll).toBeChecked(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Uncheck first todo. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').uncheck(); - - // Reuse toggleAll locator and make sure its not checked. - await expect(toggleAll).not.toBeChecked(); - - await firstTodo.getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Assert the toggle all is checked again. - await expect(toggleAll).toBeChecked(); - }); -}); - -test.describe('Item', () => { - - test('should allow me to mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - // Check first item. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').check(); - await expect(firstTodo).toHaveClass('completed'); - - // Check second item. - const secondTodo = page.getByTestId('todo-item').nth(1); - await expect(secondTodo).not.toHaveClass('completed'); - await secondTodo.getByRole('checkbox').check(); - - // Assert completed class. - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).toHaveClass('completed'); - }); - - test('should allow me to un-mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const firstTodo = page.getByTestId('todo-item').nth(0); - const secondTodo = page.getByTestId('todo-item').nth(1); - const firstTodoCheckbox = firstTodo.getByRole('checkbox'); - - await firstTodoCheckbox.check(); - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await firstTodoCheckbox.uncheck(); - await expect(firstTodo).not.toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 0); - }); - - test('should allow me to edit an item', async ({ page }) => { - await createDefaultTodos(page); - - const todoItems = page.getByTestId('todo-item'); - const secondTodo = todoItems.nth(1); - await secondTodo.dblclick(); - await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); - await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); - - // Explicitly assert the new text value. - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2] - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); -}); - -test.describe('Editing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should hide other controls when editing', async ({ page }) => { - const todoItem = page.getByTestId('todo-item').nth(1); - await todoItem.dblclick(); - await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); - await expect(todoItem.locator('label', { - hasText: TODO_ITEMS[1], - })).not.toBeVisible(); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should save edits on blur', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should trim entered text', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should remove the item if an empty text string was entered', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[2], - ]); - }); - - test('should cancel edits on escape', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); - await expect(todoItems).toHaveText(TODO_ITEMS); - }); -}); - -test.describe('Counter', () => { - test('should display the current number of todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - await expect(todoCount).toContainText('1'); - - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - await expect(todoCount).toContainText('2'); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); -}); - -test.describe('Clear completed button', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - }); - - test('should display the correct text', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); - }); - - test('should remove completed items when clicked', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).getByRole('checkbox').check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(todoItems).toHaveCount(2); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should be hidden when there are no items that are completed', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); - }); -}); - -test.describe('Persistence', () => { - test('should persist its data', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const todoItems = page.getByTestId('todo-item'); - const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); - await firstTodoCheck.check(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - - // Ensure there is 1 completed item. - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - // Now reload. - await page.reload(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - }); -}); - -test.describe('Routing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - // make sure the app had a chance to save updated todos in storage - // before navigating to a new view, otherwise the items can get lost :( - // in some frameworks like Durandal - await checkTodosInLocalStorage(page, TODO_ITEMS[0]); - }); - - test('should allow me to display active items', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await expect(todoItem).toHaveCount(2); - await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should respect the back button', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await test.step('Showing all items', async () => { - await page.getByRole('link', { name: 'All' }).click(); - await expect(todoItem).toHaveCount(3); - }); - - await test.step('Showing active items', async () => { - await page.getByRole('link', { name: 'Active' }).click(); - }); - - await test.step('Showing completed items', async () => { - await page.getByRole('link', { name: 'Completed' }).click(); - }); - - await expect(todoItem).toHaveCount(1); - await page.goBack(); - await expect(todoItem).toHaveCount(2); - await page.goBack(); - await expect(todoItem).toHaveCount(3); - }); - - test('should allow me to display completed items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Completed' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(1); - }); - - test('should allow me to display all items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await page.getByRole('link', { name: 'Completed' }).click(); - await page.getByRole('link', { name: 'All' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(3); - }); - - test('should highlight the currently applied filter', async ({ page }) => { - await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); - - //create locators for active and completed links - const activeLink = page.getByRole('link', { name: 'Active' }); - const completedLink = page.getByRole('link', { name: 'Completed' }); - await activeLink.click(); - - // Page change - active items. - await expect(activeLink).toHaveClass('selected'); - await completedLink.click(); - - // Page change - completed items. - await expect(completedLink).toHaveClass('selected'); - }); -}); - -async function createDefaultTodos(page) { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } -} - -/** - * @param {import('@playwright/test').Page} page - * @param {number} expected - */ - async function checkNumberOfTodosInLocalStorage(page, expected) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).length === e; - }, expected); -} - -/** - * @param {import('@playwright/test').Page} page - * @param {number} expected - */ - async function checkNumberOfCompletedTodosInLocalStorage(page, expected) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).filter(i => i.completed).length === e; - }, expected); -} - -/** - * @param {import('@playwright/test').Page} page - * @param {string} title - */ -async function checkTodosInLocalStorage(page, title) { - return await page.waitForFunction(t => { - return JSON.parse(localStorage['react-todos']).map(i => i.title).includes(t); - }, title); -} From 083d985a5f65427383540361f4c7fe1651703505 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 24 May 2024 17:33:00 +0200 Subject: [PATCH 07/78] Changed the jest configuration so that it doesnt try running the playwright tests --- jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.js b/jest.config.js index 7fffc9f8a..92f60d785 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,6 +4,7 @@ module.exports = { '^.+\\.vue$': 'vue-jest', }, testMatch: ['**/*.spec.js'], + testPathIgnorePatterns: ['/e2e/'], setupFilesAfterEnv: ['./tests/mocks/firebase.js'], resetMocks: true, clearMocks: true, From 4465aaebcf2e91504b3c213d81b91fd698ac933f Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 19 Apr 2024 21:32:01 +0200 Subject: [PATCH 08/78] Added the script for tools and workflow --- .github/workflows/ishikawaTools.yaml | 30 +++++ ishikawasTools.py | 162 +++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 .github/workflows/ishikawaTools.yaml create mode 100644 ishikawasTools.py diff --git a/.github/workflows/ishikawaTools.yaml b/.github/workflows/ishikawaTools.yaml new file mode 100644 index 000000000..4186eb6cd --- /dev/null +++ b/.github/workflows/ishikawaTools.yaml @@ -0,0 +1,30 @@ +name: Generate Reports + +on: + push: + branches: + - develop + +jobs: + generate-reports: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10.x' + + - name: Install dependencies + run: | + pip install matplotlib pandas requests PyGithub + + - name: Run report generation script + env: + TOKEN: ${{ secrets.TOKEN }} + USER: ${{ secrets.USER }} + PROJECT: ${{ secrets.PROJECT }} + run: python scripts.py diff --git a/ishikawasTools.py b/ishikawasTools.py new file mode 100644 index 000000000..bf028faa5 --- /dev/null +++ b/ishikawasTools.py @@ -0,0 +1,162 @@ +import os +import pandas as pd +from datetime import datetime, timedelta +from github import Github +import matplotlib.pyplot as plt +import requests +from textwrap import wrap + + +def fetch_issues(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + return issues + + +def generate_pareto_diagram(issues): + labels_count = {} + for issue in issues: + for label in issue['labels']: + label_name = label['name'] + labels_count[label_name] = labels_count.get(label_name, 0) + 1 + + sorted_labels_count = dict(sorted(labels_count.items(), key=lambda item: item[1], reverse=True)) + + labels = list(sorted_labels_count.keys()) + counts = list(sorted_labels_count.values()) + + total_issues = sum(counts) + cumulative_percentage = [sum(counts[:i + 1]) / total_issues * 100 for i in range(len(counts))] + + _, ax1 = plt.subplots() + ax1.bar(labels, counts, color='b') + ax1.set_xlabel('Labels', fontsize=12) + ax1.set_ylabel('Frequency', color='b', fontsize=12) + ax1.tick_params(axis='y', colors='b') + + ax2 = ax1.twinx() + ax2.plot(labels, cumulative_percentage, color='r', marker='o') + ax2.set_ylabel('Cumulative Percentage (%)', color='r', fontsize=12) + ax2.tick_params(axis='y', colors='r') + + plt.title('Pareto Diagram of Issues by Labels - General Report', fontsize=14) + plt.xticks(rotation=45, ha='right', fontsize=8) + ax1.set_xticklabels(['\n'.join(wrap(label, 13)) for label in labels]) + plt.tight_layout() + plt.show() + + +def generate_weekly_report(github_token, username, repository_name): + g = Github(github_token) + repo = g.get_repo(f"{username}/{repository_name}") + issues = repo.get_issues(state='all') + weekly_counts = {'Monday': {'opened': 0, 'closed': 0}, 'Tuesday': {'opened': 0, 'closed': 0}, + 'Wednesday': {'opened': 0, 'closed': 0}, 'Thursday': {'opened': 0, 'closed': 0}, + 'Friday': {'opened': 0, 'closed': 0}, 'Saturday': {'opened': 0, 'closed': 0}, + 'Sunday': {'opened': 0, 'closed': 0}} + + def get_day_of_week(date_str): + date = datetime.strptime(date_str[:10], '%Y-%m-%d') + return date.strftime('%A') + + current_date = datetime.now() + one_week_ago = current_date - timedelta(days=7) + for issue in issues: + created_at = issue.created_at.replace(tzinfo=None) + if created_at >= one_week_ago: + day_of_week = get_day_of_week(str(created_at)) + weekly_counts[day_of_week]['opened'] += 1 + if issue.closed_at: + closed_at = issue.closed_at.replace(tzinfo=None) + if closed_at >= one_week_ago: + day_of_week = get_day_of_week(str(closed_at)) + weekly_counts[day_of_week]['closed'] += 1 + + +def generate_histogram_report(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + + labels_count = { + "back-end": 0, + "bug": 0, + "database": 0, + "documentation": 0, + "front-end": 0, + "tests": 0, + "wontfix": 0, + } + + for issue in issues: + for label in issue['labels']: + label_name = label['name'] + if label_name in labels_count: + labels_count[label_name] += 1 + + plt.figure(figsize=(10, 6)) + plt.bar(labels_count.keys(), labels_count.values()) + plt.ylabel('Number of Issues') + plt.title('Histogram of Issues by Label - General Report') + plt.xticks(rotation=20) + plt.yticks(range(0, max(labels_count.values()) + 1)) + plt.show() + + +def generate_scatter_diagram_report(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + + days_to_close = [] + issue_created_dates = [] + + for issue in issues: + created_at = datetime.strptime(issue['created_at'], '%Y-%m-%dT%H:%M:%SZ') + closed_at = datetime.strptime(issue['closed_at'], '%Y-%m-%dT%H:%M:%SZ') if issue[ + 'closed_at'] else datetime.now() + time_to_close = (closed_at - created_at).days + days_to_close.append(time_to_close) + issue_created_dates.append(created_at) + + plt.figure(figsize=(10, 6)) + plt.scatter(days_to_close, issue_created_dates, color='blue', alpha=0.7) + plt.xlabel('Days for closing the issue') + plt.ylabel('Date of creation of the issue') + plt.title('Scatter Diagram of closed issues') + plt.grid(True) + plt.show() + + +def main(): + github_token = os.getenv('TOKEN') + username = os.getenv('USER') + repository_name = os.getenv('PROJECT') + generate_weekly_report(github_token, username, repository_name) + issues = fetch_issues(username, repository_name, github_token) + generate_pareto_diagram(issues) + generate_histogram_report(username, repository_name, github_token) + generate_scatter_diagram_report(username, repository_name, github_token) + + +if __name__ == "__main__": + main() \ No newline at end of file From c689647f8e05833b4e5bbb9b81fb15dd5494467d Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Fri, 19 Apr 2024 21:34:45 +0200 Subject: [PATCH 09/78] Removed the workflow file and will add it using the github ui --- .github/workflows/ishikawaTools.yaml | 30 ---------------------------- 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/ishikawaTools.yaml diff --git a/.github/workflows/ishikawaTools.yaml b/.github/workflows/ishikawaTools.yaml deleted file mode 100644 index 4186eb6cd..000000000 --- a/.github/workflows/ishikawaTools.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: Generate Reports - -on: - push: - branches: - - develop - -jobs: - generate-reports: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.10.x' - - - name: Install dependencies - run: | - pip install matplotlib pandas requests PyGithub - - - name: Run report generation script - env: - TOKEN: ${{ secrets.TOKEN }} - USER: ${{ secrets.USER }} - PROJECT: ${{ secrets.PROJECT }} - run: python scripts.py From e0fde3a2b112f24023d05b12e7e60d8d3eae0371 Mon Sep 17 00:00:00 2001 From: Zlatanius <50078303+Zlatanius@users.noreply.github.com> Date: Fri, 19 Apr 2024 21:54:16 +0200 Subject: [PATCH 10/78] Create ishikawas.yml --- .github/workflows/ishikawas.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/ishikawas.yml diff --git a/.github/workflows/ishikawas.yml b/.github/workflows/ishikawas.yml new file mode 100644 index 000000000..50f63627f --- /dev/null +++ b/.github/workflows/ishikawas.yml @@ -0,0 +1,32 @@ +name: Generate Reports + +on: + push: + branches: + - develop + schedule: + - cron: '0 0 * * *' # Run daily at midnight + +jobs: + generate-reports: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10.x' + + - name: Install dependencies + run: | + pip install matplotlib pandas requests PyGithub + + - name: Run report generation script + env: + TOKEN: ${{ secrets.TOKEN }} + USER: ${{ secrets.USER }} + PROJECT: ${{ secrets.PROJECT }} + run: python scripts.py From 5ef101993bf833c1773523559074023798b5da25 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Tue, 28 May 2024 16:36:12 +0200 Subject: [PATCH 11/78] Added the workflow file and scripts for generation of ishikawa tools diagrams --- .github/workflows/ishikawa-tools.yml | 35 ++++ ishikawa_tools/ishikawa_tools_script.py | 209 ++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 .github/workflows/ishikawa-tools.yml create mode 100644 ishikawa_tools/ishikawa_tools_script.py diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml new file mode 100644 index 000000000..7d62783ef --- /dev/null +++ b/.github/workflows/ishikawa-tools.yml @@ -0,0 +1,35 @@ +name: Generate Reports + +on: + push: + branches: + - ishikawas-tools + +jobs: + generate-reports: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10.x' + + - name: Install dependencies + run: | + pip install matplotlib pandas requests PyGithub + + - name: Run report generation script + env: + TOKEN: ${{ secrets.TOKEN }} + USER: ${{ secrets.USER }} + PROJECT: ${{ secrets.PROJECT }} + run: python ishikawa_tools/ishikawa_tools_script.py + - uses: actions/upload-artifact@v4 + with: + name: ishikawa-screenshots + path: ./ishikawa_tools/output + retention-days: 30 diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py new file mode 100644 index 000000000..42798df0d --- /dev/null +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -0,0 +1,209 @@ +import os +import pandas as pd +from datetime import datetime, timedelta +from github import Github +import matplotlib.pyplot as plt +import requests +from textwrap import wrap +from pathlib import Path + + +def fetch_issues(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + return issues + + +def generate_pareto_diagram(issues): + labels_count = {} + for issue in issues: + for label in issue['labels']: + label_name = label['name'] + labels_count[label_name] = labels_count.get(label_name, 0) + 1 + + sorted_labels_count = dict(sorted(labels_count.items(), key=lambda item: item[1], reverse=True)) + + labels = list(sorted_labels_count.keys()) + counts = list(sorted_labels_count.values()) + + total_issues = sum(counts) + cumulative_percentage = [sum(counts[:i + 1]) / total_issues * 100 for i in range(len(counts))] + + _, ax1 = plt.subplots() + ax1.bar(labels, counts, color='b') + ax1.set_xlabel('Labels', fontsize=12) + ax1.set_ylabel('Frequency', color='b', fontsize=12) + ax1.tick_params(axis='y', colors='b') + + ax2 = ax1.twinx() + ax2.plot(labels, cumulative_percentage, color='r', marker='o') + ax2.set_ylabel('Cumulative Percentage (%)', color='r', fontsize=12) + ax2.tick_params(axis='y', colors='r') + + plt.title('Pareto Diagram of Issues by Labels - General Report', fontsize=14) + plt.xticks(rotation=45, ha='right', fontsize=8) + ax1.set_xticklabels(['\n'.join(wrap(label, 13)) for label in labels]) + plt.tight_layout() + plt.savefig('./ishikawa_tools/output/pereto.pdf') + + +def generate_weekly_report(github_token, username, repository_name): + # Crear una instancia de la clase Github + g = Github(github_token) + + # Obtener el repositorio + repo = g.get_repo(f"{username}/{repository_name}") + + # Obtener todas las issues del repositorio + issues = repo.get_issues(state='all') + + # Diccionario para almacenar el recuento de issues por día de la semana + weekly_counts = { + 'Monday': {'opened': 0, 'closed': 0}, + 'Tuesday': {'opened': 0, 'closed': 0}, + 'Wednesday': {'opened': 0, 'closed': 0}, + 'Thursday': {'opened': 0, 'closed': 0}, + 'Friday': {'opened': 0, 'closed': 0}, + 'Saturday': {'opened': 0, 'closed': 0}, + 'Sunday': {'opened': 0, 'closed': 0} + } + + def get_day_of_week(date_str): + date = datetime.strptime(date_str[:10], '%Y-%m-%d') + return date.strftime('%A') + + current_date = datetime.now() + one_week_ago = current_date - timedelta(days=7) + + for issue in issues: + created_at = issue.created_at.replace(tzinfo=None) + if created_at >= one_week_ago: + day_of_week = get_day_of_week(str(created_at)) + weekly_counts[day_of_week]['opened'] += 1 + + if issue.closed_at: + closed_at = issue.closed_at.replace(tzinfo=None) + if closed_at >= one_week_ago: + day_of_week = get_day_of_week(str(closed_at)) + weekly_counts[day_of_week]['closed'] += 1 + + # Extraer los datos para la tabla + dias = list(weekly_counts.keys()) + abiertas = [weekly_counts[d]["opened"] for d in weekly_counts] + cerradas = [weekly_counts[d]["closed"] for d in weekly_counts] + + data = { + "Día de la Semana": dias, + "Abiertas": abiertas, + "Cerradas": cerradas + } + + # Crear la tabla + df = pd.DataFrame(data) + + # Crear figura y eje + fig, ax = plt.subplots() + + # Eliminar marcas del eje + ax.axis('off') + + # Crear tabla + tabla = ax.table(cellText=df.values, + colLabels=df.columns, + cellLoc='center', + loc='center') + + # Ajustar tamaño de la fuente + tabla.auto_set_font_size(False) + tabla.set_fontsize(12) + + # Ajustar tamaño de la tabla + tabla.scale(1.5, 1.5) + plt.savefig('./ishikawa_tools/output/checklist.pdf') + + +def generate_histogram_report(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + + labels_count = { + } + + for issue in issues: + for label in issue['labels']: + label_name = label['name'] + if label_name in labels_count: + labels_count[label_name] += 1 + else: + labels_count[label_name] = 1 + + plt.figure(figsize=(10, 6)) + plt.bar(labels_count.keys(), labels_count.values()) + plt.ylabel('Number of Issues') + plt.title('Histogram of Issues by Label - General Report') + plt.xticks(rotation=20) + plt.yticks(range(0, max(labels_count.values()) + 1)) + plt.savefig('./ishikawa_tools/output/histogram.pdf') + + +def generate_scatter_diagram_report(repo_owner, repo_name, github_token): + url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" + headers = {'Authorization': f'token {github_token}'} + response = requests.get(url, headers=headers) + if response.status_code != 200: + print(f"Failed to fetch issues. Status code: {response.status_code}") + print(response.text) + return None + else: + issues = response.json() + + days_to_close = [] + issue_created_dates = [] + + for issue in issues: + created_at = datetime.strptime(issue['created_at'], '%Y-%m-%dT%H:%M:%SZ') + closed_at = datetime.strptime(issue['closed_at'], '%Y-%m-%dT%H:%M:%SZ') if issue[ + 'closed_at'] else datetime.now() + time_to_close = (closed_at - created_at).days + days_to_close.append(time_to_close) + issue_created_dates.append(created_at) + + plt.figure(figsize=(10, 6)) + plt.scatter(days_to_close, issue_created_dates, color='blue', alpha=0.7) + plt.xlabel('Days for closing the issue') + plt.ylabel('Date of creation of the issue') + plt.title('Scatter Diagram of closed issues') + plt.grid(True) + plt.savefig('./ishikawa_tools/output/scatter.pdf') + + +def main(): + github_token = os.getenv('TOKEN') + username = os.getenv('USER') + repository_name = os.getenv('PROJECT') + + issues = fetch_issues(username, repository_name, github_token) + Path("./ishikawa_tools/output").mkdir(parents=True, exist_ok=True) + + generate_pareto_diagram(issues) + generate_histogram_report(username, repository_name, github_token) + generate_scatter_diagram_report(username, repository_name, github_token) + generate_weekly_report(github_token, username, repository_name) + + +if __name__ == "__main__": + main() From e86fce24c553a06f3735ac4504db46f9882685bc Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Tue, 28 May 2024 16:42:18 +0200 Subject: [PATCH 12/78] Removed old workflow file --- .github/workflows/ishikawas.yml | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/workflows/ishikawas.yml diff --git a/.github/workflows/ishikawas.yml b/.github/workflows/ishikawas.yml deleted file mode 100644 index 50f63627f..000000000 --- a/.github/workflows/ishikawas.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Generate Reports - -on: - push: - branches: - - develop - schedule: - - cron: '0 0 * * *' # Run daily at midnight - -jobs: - generate-reports: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.10.x' - - - name: Install dependencies - run: | - pip install matplotlib pandas requests PyGithub - - - name: Run report generation script - env: - TOKEN: ${{ secrets.TOKEN }} - USER: ${{ secrets.USER }} - PROJECT: ${{ secrets.PROJECT }} - run: python scripts.py From 68b12b9db3dd2895226f1ecfac685a2df2ab4498 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Tue, 28 May 2024 17:13:07 +0200 Subject: [PATCH 13/78] Changed the trigger for ishikawa action to daily and on issue events --- .github/workflows/ishikawa-tools.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index 7d62783ef..1b4480a7c 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -1,9 +1,10 @@ name: Generate Reports on: - push: - branches: - - ishikawas-tools + schedule: + - cron: "0 0 * * *" + issues: + types: [opened, deleted, closed, reopened, labeled] jobs: generate-reports: @@ -32,4 +33,4 @@ jobs: with: name: ishikawa-screenshots path: ./ishikawa_tools/output - retention-days: 30 + retention-days: 1 From 02b72340a6f0126a296d26eb6ed71c32469e66aa Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Tue, 28 May 2024 17:33:16 +0200 Subject: [PATCH 14/78] Changed the ishikawa action from using a personal access token to using the default GITHUB_TOKEN --- .github/workflows/ishikawa-tools.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index 1b4480a7c..b696ad5f1 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -25,7 +25,7 @@ jobs: - name: Run report generation script env: - TOKEN: ${{ secrets.TOKEN }} + TOKEN: ${{ secrets.GITHUB_TOKEN }} USER: ${{ secrets.USER }} PROJECT: ${{ secrets.PROJECT }} run: python ishikawa_tools/ishikawa_tools_script.py From 5dcc9f959a082ff793aefb97e3889e2f3f0ff1df Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Tue, 28 May 2024 17:38:37 +0200 Subject: [PATCH 15/78] Removed the old ishikawa scripts file --- ishikawasTools.py | 162 ---------------------------------------------- 1 file changed, 162 deletions(-) delete mode 100644 ishikawasTools.py diff --git a/ishikawasTools.py b/ishikawasTools.py deleted file mode 100644 index bf028faa5..000000000 --- a/ishikawasTools.py +++ /dev/null @@ -1,162 +0,0 @@ -import os -import pandas as pd -from datetime import datetime, timedelta -from github import Github -import matplotlib.pyplot as plt -import requests -from textwrap import wrap - - -def fetch_issues(repo_owner, repo_name, github_token): - url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" - headers = {'Authorization': f'token {github_token}'} - response = requests.get(url, headers=headers) - if response.status_code != 200: - print(f"Failed to fetch issues. Status code: {response.status_code}") - print(response.text) - return None - else: - issues = response.json() - return issues - - -def generate_pareto_diagram(issues): - labels_count = {} - for issue in issues: - for label in issue['labels']: - label_name = label['name'] - labels_count[label_name] = labels_count.get(label_name, 0) + 1 - - sorted_labels_count = dict(sorted(labels_count.items(), key=lambda item: item[1], reverse=True)) - - labels = list(sorted_labels_count.keys()) - counts = list(sorted_labels_count.values()) - - total_issues = sum(counts) - cumulative_percentage = [sum(counts[:i + 1]) / total_issues * 100 for i in range(len(counts))] - - _, ax1 = plt.subplots() - ax1.bar(labels, counts, color='b') - ax1.set_xlabel('Labels', fontsize=12) - ax1.set_ylabel('Frequency', color='b', fontsize=12) - ax1.tick_params(axis='y', colors='b') - - ax2 = ax1.twinx() - ax2.plot(labels, cumulative_percentage, color='r', marker='o') - ax2.set_ylabel('Cumulative Percentage (%)', color='r', fontsize=12) - ax2.tick_params(axis='y', colors='r') - - plt.title('Pareto Diagram of Issues by Labels - General Report', fontsize=14) - plt.xticks(rotation=45, ha='right', fontsize=8) - ax1.set_xticklabels(['\n'.join(wrap(label, 13)) for label in labels]) - plt.tight_layout() - plt.show() - - -def generate_weekly_report(github_token, username, repository_name): - g = Github(github_token) - repo = g.get_repo(f"{username}/{repository_name}") - issues = repo.get_issues(state='all') - weekly_counts = {'Monday': {'opened': 0, 'closed': 0}, 'Tuesday': {'opened': 0, 'closed': 0}, - 'Wednesday': {'opened': 0, 'closed': 0}, 'Thursday': {'opened': 0, 'closed': 0}, - 'Friday': {'opened': 0, 'closed': 0}, 'Saturday': {'opened': 0, 'closed': 0}, - 'Sunday': {'opened': 0, 'closed': 0}} - - def get_day_of_week(date_str): - date = datetime.strptime(date_str[:10], '%Y-%m-%d') - return date.strftime('%A') - - current_date = datetime.now() - one_week_ago = current_date - timedelta(days=7) - for issue in issues: - created_at = issue.created_at.replace(tzinfo=None) - if created_at >= one_week_ago: - day_of_week = get_day_of_week(str(created_at)) - weekly_counts[day_of_week]['opened'] += 1 - if issue.closed_at: - closed_at = issue.closed_at.replace(tzinfo=None) - if closed_at >= one_week_ago: - day_of_week = get_day_of_week(str(closed_at)) - weekly_counts[day_of_week]['closed'] += 1 - - -def generate_histogram_report(repo_owner, repo_name, github_token): - url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" - headers = {'Authorization': f'token {github_token}'} - response = requests.get(url, headers=headers) - if response.status_code != 200: - print(f"Failed to fetch issues. Status code: {response.status_code}") - print(response.text) - return None - else: - issues = response.json() - - labels_count = { - "back-end": 0, - "bug": 0, - "database": 0, - "documentation": 0, - "front-end": 0, - "tests": 0, - "wontfix": 0, - } - - for issue in issues: - for label in issue['labels']: - label_name = label['name'] - if label_name in labels_count: - labels_count[label_name] += 1 - - plt.figure(figsize=(10, 6)) - plt.bar(labels_count.keys(), labels_count.values()) - plt.ylabel('Number of Issues') - plt.title('Histogram of Issues by Label - General Report') - plt.xticks(rotation=20) - plt.yticks(range(0, max(labels_count.values()) + 1)) - plt.show() - - -def generate_scatter_diagram_report(repo_owner, repo_name, github_token): - url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" - headers = {'Authorization': f'token {github_token}'} - response = requests.get(url, headers=headers) - if response.status_code != 200: - print(f"Failed to fetch issues. Status code: {response.status_code}") - print(response.text) - return None - else: - issues = response.json() - - days_to_close = [] - issue_created_dates = [] - - for issue in issues: - created_at = datetime.strptime(issue['created_at'], '%Y-%m-%dT%H:%M:%SZ') - closed_at = datetime.strptime(issue['closed_at'], '%Y-%m-%dT%H:%M:%SZ') if issue[ - 'closed_at'] else datetime.now() - time_to_close = (closed_at - created_at).days - days_to_close.append(time_to_close) - issue_created_dates.append(created_at) - - plt.figure(figsize=(10, 6)) - plt.scatter(days_to_close, issue_created_dates, color='blue', alpha=0.7) - plt.xlabel('Days for closing the issue') - plt.ylabel('Date of creation of the issue') - plt.title('Scatter Diagram of closed issues') - plt.grid(True) - plt.show() - - -def main(): - github_token = os.getenv('TOKEN') - username = os.getenv('USER') - repository_name = os.getenv('PROJECT') - generate_weekly_report(github_token, username, repository_name) - issues = fetch_issues(username, repository_name, github_token) - generate_pareto_diagram(issues) - generate_histogram_report(username, repository_name, github_token) - generate_scatter_diagram_report(username, repository_name, github_token) - - -if __name__ == "__main__": - main() \ No newline at end of file From f4f4e7a2febe2023c3d1b2926e9dc91922342d07 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 16:09:30 -0300 Subject: [PATCH 16/78] commit test --- src/components/organisms/ModeratedCoopsView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/organisms/ModeratedCoopsView.vue b/src/components/organisms/ModeratedCoopsView.vue index 4c77db7ed..b6bce6981 100644 --- a/src/components/organisms/ModeratedCoopsView.vue +++ b/src/components/organisms/ModeratedCoopsView.vue @@ -48,7 +48,7 @@ Date: Wed, 29 May 2024 17:03:33 -0300 Subject: [PATCH 17/78] fix: tokens name on ishikawa functions --- .github/workflows/ishikawa-tools.yml | 2 +- ishikawa_tools/ishikawa_tools_script.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index b696ad5f1..1d7281291 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -25,7 +25,7 @@ jobs: - name: Run report generation script env: - TOKEN: ${{ secrets.GITHUB_TOKEN }} + TOKEN: ${{ secrets.ACCESS_TOKEN }} USER: ${{ secrets.USER }} PROJECT: ${{ secrets.PROJECT }} run: python ishikawa_tools/ishikawa_tools_script.py diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py index 42798df0d..dc7b53cd9 100644 --- a/ishikawa_tools/ishikawa_tools_script.py +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -192,7 +192,7 @@ def generate_scatter_diagram_report(repo_owner, repo_name, github_token): def main(): - github_token = os.getenv('TOKEN') + github_token = os.getenv('USER_TOKEN') username = os.getenv('USER') repository_name = os.getenv('PROJECT') From 1e3aa876c99c3860199ca314dfdf44875999bbd2 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:07:22 -0300 Subject: [PATCH 18/78] Fix: wrong secret name --- ishikawa_tools/ishikawa_tools_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py index dc7b53cd9..34cec5b6b 100644 --- a/ishikawa_tools/ishikawa_tools_script.py +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -192,7 +192,7 @@ def generate_scatter_diagram_report(repo_owner, repo_name, github_token): def main(): - github_token = os.getenv('USER_TOKEN') + github_token = os.getenv('ACCESS_TOKEN') username = os.getenv('USER') repository_name = os.getenv('PROJECT') From 90e1d1dc8516250f0e420f0bef224b712474d080 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:20:30 -0300 Subject: [PATCH 19/78] feat: check variables --- .github/workflows/ishikawa-tools.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index 1d7281291..bc6cc9b13 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -23,6 +23,12 @@ jobs: run: | pip install matplotlib pandas requests PyGithub + - name: Check environment variables + run: | + echo "User: $USER" + echo "Project: $PROJECT" + echo "Token: ${#ACCESS_TOKEN}" # This will print the length of the token to ensure it's set, without exposing it. + - name: Run report generation script env: TOKEN: ${{ secrets.ACCESS_TOKEN }} From 1c96c382c1142e63ce8f422a9359ae317c1832db Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:27:51 -0300 Subject: [PATCH 20/78] fix: run job wrong place --- .github/workflows/ishikawa-tools.yml | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index bc6cc9b13..88c8a8b79 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -2,7 +2,7 @@ name: Generate Reports on: schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' issues: types: [opened, deleted, closed, reopened, labeled] @@ -11,32 +11,32 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.10.x' + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.10.x' - - name: Install dependencies - run: | - pip install matplotlib pandas requests PyGithub + - name: Install dependencies + run: | + pip install matplotlib pandas requests PyGithub - - name: Check environment variables - run: | - echo "User: $USER" - echo "Project: $PROJECT" - echo "Token: ${#ACCESS_TOKEN}" # This will print the length of the token to ensure it's set, without exposing it. + - name: Check environment variables + run: | + echo "User: $USER" + echo "Project: $PROJECT" + echo "Token: ${#ACCESS_TOKEN}" # This will print the length of the token to ensure it's set, without exposing it. - - name: Run report generation script - env: - TOKEN: ${{ secrets.ACCESS_TOKEN }} - USER: ${{ secrets.USER }} - PROJECT: ${{ secrets.PROJECT }} - run: python ishikawa_tools/ishikawa_tools_script.py - - uses: actions/upload-artifact@v4 - with: - name: ishikawa-screenshots - path: ./ishikawa_tools/output - retention-days: 1 + - name: Run report generation script + env: + TOKEN: ${{ secrets.ACCESS_TOKEN }} + USER: ${{ secrets.USER }} + PROJECT: ${{ secrets.PROJECT }} + run: python ishikawa_tools/ishikawa_tools_script.py + - uses: actions/upload-artifact@v4 + with: + name: ishikawa-screenshots + path: ./ishikawa_tools/output + retention-days: 1 From b51f0b9d158c4bd3c29d1bb9ce14539e32675220 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:30:38 -0300 Subject: [PATCH 21/78] fix: changed name of env secret --- .github/workflows/ishikawa-tools.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index 88c8a8b79..37014975a 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -31,7 +31,7 @@ jobs: - name: Run report generation script env: - TOKEN: ${{ secrets.ACCESS_TOKEN }} + ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} USER: ${{ secrets.USER }} PROJECT: ${{ secrets.PROJECT }} run: python ishikawa_tools/ishikawa_tools_script.py From ce50163908470ec22864be0cdde1267966435a38 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:35:57 -0300 Subject: [PATCH 22/78] fix: ishikawa python and yml --- .github/workflows/ishikawa-tools.yml | 9 +++- ishikawa_tools/ishikawa_tools_script.py | 57 +++++++------------------ 2 files changed, 22 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ishikawa-tools.yml b/.github/workflows/ishikawa-tools.yml index 37014975a..755077c97 100644 --- a/.github/workflows/ishikawa-tools.yml +++ b/.github/workflows/ishikawa-tools.yml @@ -24,17 +24,22 @@ jobs: pip install matplotlib pandas requests PyGithub - name: Check environment variables + env: + ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} + USER: ${{ secrets.USER }} + PROJECT: ${{ secrets.PROJECT }} run: | echo "User: $USER" echo "Project: $PROJECT" - echo "Token: ${#ACCESS_TOKEN}" # This will print the length of the token to ensure it's set, without exposing it. + echo "Token length: ${#ACCESS_TOKEN}" # This will print the length of the token to ensure it's set, without exposing it. - name: Run report generation script env: - ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} + TOKEN: ${{ secrets.ACCESS_TOKEN }} USER: ${{ secrets.USER }} PROJECT: ${{ secrets.PROJECT }} run: python ishikawa_tools/ishikawa_tools_script.py + - uses: actions/upload-artifact@v4 with: name: ishikawa-screenshots diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py index 34cec5b6b..4c407a9f1 100644 --- a/ishikawa_tools/ishikawa_tools_script.py +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -7,19 +7,16 @@ from textwrap import wrap from pathlib import Path - def fetch_issues(repo_owner, repo_name, github_token): url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" headers = {'Authorization': f'token {github_token}'} response = requests.get(url, headers=headers) if response.status_code != 200: print(f"Failed to fetch issues. Status code: {response.status_code}") - print(response.text) + print(response.json()) # Print the full error message return None else: - issues = response.json() - return issues - + return response.json() def generate_pareto_diagram(issues): labels_count = {} @@ -53,18 +50,11 @@ def generate_pareto_diagram(issues): plt.tight_layout() plt.savefig('./ishikawa_tools/output/pereto.pdf') - def generate_weekly_report(github_token, username, repository_name): - # Crear una instancia de la clase Github g = Github(github_token) - - # Obtener el repositorio repo = g.get_repo(f"{username}/{repository_name}") - - # Obtener todas las issues del repositorio issues = repo.get_issues(state='all') - # Diccionario para almacenar el recuento de issues por día de la semana weekly_counts = { 'Monday': {'opened': 0, 'closed': 0}, 'Tuesday': {'opened': 0, 'closed': 0}, @@ -94,7 +84,6 @@ def get_day_of_week(date_str): day_of_week = get_day_of_week(str(closed_at)) weekly_counts[day_of_week]['closed'] += 1 - # Extraer los datos para la tabla dias = list(weekly_counts.keys()) abiertas = [weekly_counts[d]["opened"] for d in weekly_counts] cerradas = [weekly_counts[d]["closed"] for d in weekly_counts] @@ -105,30 +94,17 @@ def get_day_of_week(date_str): "Cerradas": cerradas } - # Crear la tabla df = pd.DataFrame(data) - # Crear figura y eje fig, ax = plt.subplots() - - # Eliminar marcas del eje ax.axis('off') + tabla = ax.table(cellText=df.values, colLabels=df.columns, cellLoc='center', loc='center') - # Crear tabla - tabla = ax.table(cellText=df.values, - colLabels=df.columns, - cellLoc='center', - loc='center') - - # Ajustar tamaño de la fuente tabla.auto_set_font_size(False) tabla.set_fontsize(12) - - # Ajustar tamaño de la tabla tabla.scale(1.5, 1.5) plt.savefig('./ishikawa_tools/output/checklist.pdf') - def generate_histogram_report(repo_owner, repo_name, github_token): url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" headers = {'Authorization': f'token {github_token}'} @@ -140,16 +116,11 @@ def generate_histogram_report(repo_owner, repo_name, github_token): else: issues = response.json() - labels_count = { - } - + labels_count = {} for issue in issues: for label in issue['labels']: label_name = label['name'] - if label_name in labels_count: - labels_count[label_name] += 1 - else: - labels_count[label_name] = 1 + labels_count[label_name] = labels_count.get(label_name, 0) + 1 plt.figure(figsize=(10, 6)) plt.bar(labels_count.keys(), labels_count.values()) @@ -159,7 +130,6 @@ def generate_histogram_report(repo_owner, repo_name, github_token): plt.yticks(range(0, max(labels_count.values()) + 1)) plt.savefig('./ishikawa_tools/output/histogram.pdf') - def generate_scatter_diagram_report(repo_owner, repo_name, github_token): url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/issues" headers = {'Authorization': f'token {github_token}'} @@ -176,8 +146,7 @@ def generate_scatter_diagram_report(repo_owner, repo_name, github_token): for issue in issues: created_at = datetime.strptime(issue['created_at'], '%Y-%m-%dT%H:%M:%SZ') - closed_at = datetime.strptime(issue['closed_at'], '%Y-%m-%dT%H:%M:%SZ') if issue[ - 'closed_at'] else datetime.now() + closed_at = datetime.strptime(issue['closed_at'], '%Y-%m-%dT%H:%M:%SZ') if issue['closed_at'] else datetime.now() time_to_close = (closed_at - created_at).days days_to_close.append(time_to_close) issue_created_dates.append(created_at) @@ -190,20 +159,24 @@ def generate_scatter_diagram_report(repo_owner, repo_name, github_token): plt.grid(True) plt.savefig('./ishikawa_tools/output/scatter.pdf') - def main(): - github_token = os.getenv('ACCESS_TOKEN') + github_token = os.getenv('TOKEN') username = os.getenv('USER') repository_name = os.getenv('PROJECT') + if not all([github_token, username, repository_name]): + print("One or more environment variables are missing.") + return + issues = fetch_issues(username, repository_name, github_token) - Path("./ishikawa_tools/output").mkdir(parents=True, exist_ok=True) + if issues is None: + print("Exiting script due to fetch issues failure.") + return generate_pareto_diagram(issues) + generate_weekly_report(github_token, username, repository_name) generate_histogram_report(username, repository_name, github_token) generate_scatter_diagram_report(username, repository_name, github_token) - generate_weekly_report(github_token, username, repository_name) - if __name__ == "__main__": main() From 89db3cbb59920677d807fb1581aa134d190798c1 Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:48:46 -0300 Subject: [PATCH 23/78] fix: added repo owner --- ishikawa_tools/ishikawa_tools_script.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py index 4c407a9f1..daf3c9b37 100644 --- a/ishikawa_tools/ishikawa_tools_script.py +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -160,6 +160,7 @@ def generate_scatter_diagram_report(repo_owner, repo_name, github_token): plt.savefig('./ishikawa_tools/output/scatter.pdf') def main(): + repo_owner = "marcgc21" github_token = os.getenv('TOKEN') username = os.getenv('USER') repository_name = os.getenv('PROJECT') From b6740b8da46e7d9c91c94bc45a383b363028211b Mon Sep 17 00:00:00 2001 From: jvJUCA Date: Wed, 29 May 2024 17:49:13 -0300 Subject: [PATCH 24/78] fix: repo_owner added --- ishikawa_tools/ishikawa_tools_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ishikawa_tools/ishikawa_tools_script.py b/ishikawa_tools/ishikawa_tools_script.py index daf3c9b37..abd7702ca 100644 --- a/ishikawa_tools/ishikawa_tools_script.py +++ b/ishikawa_tools/ishikawa_tools_script.py @@ -169,7 +169,7 @@ def main(): print("One or more environment variables are missing.") return - issues = fetch_issues(username, repository_name, github_token) + issues = fetch_issues(repo_owner, repository_name, github_token) if issues is None: print("Exiting script due to fetch issues failure.") return From ed47bd3454d23a41e103567607e3e2eea0881de4 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Thu, 30 May 2024 21:55:30 +0200 Subject: [PATCH 25/78] Cleaned up the plawright tests file --- e2e/ruxailabtest.spec.js | 102 +++++++++++++++------------------------ 1 file changed, 40 insertions(+), 62 deletions(-) diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 89e8c76f7..9c5464294 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -1,27 +1,28 @@ const { test, expect } = require('@playwright/test') +const { log } = require('console') -test('has link page', async ({ page }) => { - await page.goto('https://ruxailab-prod.web.app/') +const logIn = async (page) => { + await page.goto('https://ruxailab-prod.web.app/signin') - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/RUXAILAB/) -}) + await page.getByLabel('E-mail').fill('testemail@gmail.com') + await page.getByLabel('Password', { exact: true }).fill('password123') -test('sign and create heurisic test', async ({ page }) => { - await page.goto('https://ruxailab-prod.web.app/signin') await page - .getByRole('textbox', { name: 'E-mail' }) - .fill('testemail@gmail.com') - await page.getByRole('textbox', { name: 'Password' }).fill('password123') - await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') + .getByRole('main') + .getByRole('button', { name: 'Sign-In' }) + .click() +} +const createTest = async (page, type) => { await page.click( 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - await page.waitForTimeout(2000) // 2 segundo de delay + ) // Click new test button + await page.click('.card-title:has-text("Create a blank test")') - await page.click('.card.col-sm-10.col-md-5.col-10') + type === 'heuristic' && (await page.click('.card.col-sm-10.col-md-5.col-10')) // Press heuristic test card + type === 'usability' && (await page.click('.card.col-sm-10.col-md-5.col-12')) // Press usability test card + await page .getByRole('textbox', { name: 'Test Name' }) .fill('Test heuristic playwright') @@ -31,67 +32,45 @@ test('sign and create heurisic test', async ({ page }) => { await page.click( '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', - ) - // back console - await page.waitForTimeout(2000) // 2 segundo de delay + ) // Click create test button + + type === 'usability' && (await page.click('.card.col-sm-10.col-md-4.col-10')) // Click self test card + await page.click( '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) + ) // Click go back to console button +} + +test('has link page', async ({ page }) => { + await page.goto('https://ruxailab-prod.web.app/') + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/RUXAILAB/) }) -test('sign and create usability test', async ({ page }) => { - /*login*/ - await page.goto('https://ruxailab-prod.web.app/signin') - await page.waitForTimeout(2000) // 2 segundo de delay - await page - .getByRole('textbox', { name: 'E-mail' }) - .fill('testemail@gmail.com') - await page.getByRole('textbox', { name: 'Password' }).fill('password123') - await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') +test('sign and create heurisic test', async ({ page }) => { + await logIn(page) - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - await page.waitForTimeout(2000) // 2 segundo de delay - await page.click('.card-title:has-text("Create a blank test")') - await page.click('.card.col-sm-10.col-md-5.col-12') - await page - .getByRole('textbox', { name: 'Test Name' }) - .fill('Test usability playwright') - await page - .getByRole('textbox', { name: 'Test Description' }) - .fill('Some descripton') + await createTest(page, 'heuristic') +}) - await page.click( - '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', - ) - // type test - await page.click('.card.col-sm-10.col-md-4.col-10') /*selfTEst */ +test('sign and create usability test', async ({ page }) => { + await logIn(page) - // back console - await page.click( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) + await createTest(page, 'usability') }) test('sign and create template', async ({ page }) => { /*login*/ - await page.goto('https://ruxailab-prod.web.app/signin') - await page.waitForTimeout(2000) // 2 segundo de delay - await page - .getByRole('textbox', { name: 'E-mail' }) - .fill('testemail@gmail.com') - await page.getByRole('textbox', { name: 'Password' }).fill('password123') - await page.click('.v-btn.v-btn--is-elevated.v-btn--has-bg.v-btn--rounded') + await logIn(page) await page.click( 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - await page.waitForTimeout(2000) // 2 segundo de delay + ) // Click create new test button await page.click('.card-title:has-text("Create from template")') + //create MARCTEST - await page.click('.v-list-item.v-list-item--link.theme--light') - await page.waitForTimeout(2000) // 2 segundo de delay + await page.click('.v-list-item.v-list-item--link.theme--light') // Select template await page.getByRole('button', { name: 'NEXT' }).click() await page .getByRole('textbox', { name: 'Title' }) @@ -99,10 +78,9 @@ test('sign and create template', async ({ page }) => { await page .getByRole('textbox', { name: 'Description' }) .fill('Some description for template') - await page.waitForTimeout(2000) // 2 segundo de delay await page.getByRole('button', { name: 'CREATE' }).click() - // back console + await page.click( '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) + ) // Click go back to console button }) From 99d7272d6739ba4dcf1d79ef2944e5c4c1ed283b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 14:24:30 +0200 Subject: [PATCH 26/78] create dockerfile for firebase emulator --- dockerfile => Dockerfile | 2 +- docker-compose.yml | 33 ++++++++++++++++++++++++++++++++ firebase-emulator/Dockerfile | 37 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) rename dockerfile => Dockerfile (96%) create mode 100644 docker-compose.yml create mode 100644 firebase-emulator/Dockerfile diff --git a/dockerfile b/Dockerfile similarity index 96% rename from dockerfile rename to Dockerfile index 6069a6e75..a26c1fe76 100644 --- a/dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN npm install COPY . . # Run build as per the script defined in package.json -RUN npm run build +RUN npm run build-dev # Production stage using a minimal Node.js image FROM node:alpine AS production-stage diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..c4f21fd46 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + uxremotelab: + build: + context: . + dockerfile: Dockerfile + ports: + - "4321:5000" + env_file: + - .env + depends_on: + - firebase-emulator + + firebase-emulator: + build: + context: ./firebase-emulator + ports: + - "9099:9099" + - "5001:5001" + - "8081:8081" + - "5002:5002" + - "9199:9199" + - "4000:4000" + - "4400:4400" + - "4500:4500" + - "9150:9150" + - "5007:5007" + volumes: + - ./firebase-emulator:/app + environment: + - FIREBASE_PROJECT_ID=retlab-dev + # Agrega cualquier otra variable de entorno necesaria para el emulador de Firebase diff --git a/firebase-emulator/Dockerfile b/firebase-emulator/Dockerfile new file mode 100644 index 000000000..4a76a9345 --- /dev/null +++ b/firebase-emulator/Dockerfile @@ -0,0 +1,37 @@ +# We chose node-14 since currently firebase functions work on node-14 +# As from now node-16 is currently in beta for firebase functions +# But if you want to run the beta you can change node:14-alpine to node:16-alpine +# https://firebase.google.com/docs/functions/manage-functions#set_nodejs_version +FROM openjdk:11 + +# Instala Node.js +RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - && \ + apt-get install -y nodejs + +# Install the firebase cli +RUN npm install -g firebase-tools + +# Install and setup all the Firebase emulators +RUN firebase setup:emulators:database +RUN firebase setup:emulators:firestore +RUN firebase setup:emulators:storage +RUN firebase setup:emulators:ui + +# Mount your firebase project directory to /app when running the container +# This is the folder containing the firebase.json +WORKDIR /firebase-emulator + +# Copia los archivos de configuración de Firebase al contenedor +COPY firebase.json . +COPY firestore.rules . +COPY firestore.indexes.json . +COPY storage.rules . + +# Expose the emulator ports +# If you use non standard ports change them to the ones in your firebase.json +# AUTH FUNC STORE FIRE UI emulator ports +EXPOSE 9099 5001 8081 5002 9199 4000 4400 4500 9150 5007 + +# When startup of the container is complete this is the command that will be executed +# In our case we want to start the firebase emulator suite +CMD ["firebase", "emulators:start", "--project", "retlab-dev"] From 78a479050398d9aa536a4b1208403348e01769c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 14:26:18 +0200 Subject: [PATCH 27/78] firebase config for docker compose --- firebase-emulator/firebase.json | 64 ++++++++++++++++++++++++ firebase-emulator/firestore.indexes.json | 4 ++ firebase-emulator/firestore.rules | 9 ++++ firebase-emulator/storage.rules | 12 +++++ 4 files changed, 89 insertions(+) create mode 100644 firebase-emulator/firebase.json create mode 100644 firebase-emulator/firestore.indexes.json create mode 100644 firebase-emulator/firestore.rules create mode 100644 firebase-emulator/storage.rules diff --git a/firebase-emulator/firebase.json b/firebase-emulator/firebase.json new file mode 100644 index 000000000..2d377c041 --- /dev/null +++ b/firebase-emulator/firebase.json @@ -0,0 +1,64 @@ +{ + "firestore": { + "rules": "firestore.rules", + "indexes": "firestore.indexes.json" + }, + "functions": { + "predeploy": ["npm --prefix \"$RESOURCE_DIR\" run lint"], + "source": "functions" + }, + "hosting": [ + { + "site": "ruxailab-dev", + "public": "dist", + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + }, + { + "site": "ruxailab-prod", + "public": "dist", + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } + ], + "emulators": { + "auth": { + "port": 9099, + "host": "0.0.0.0" + }, + "functions": { + "port": 5001, + "host": "0.0.0.0" + }, + "firestore": { + "port": 8081, + "host": "0.0.0.0" + }, + "hosting": { + "port": 5002, + "host": "0.0.0.0" + }, + "ui": { + "enabled": true, + "port": 4000, + "host": "0.0.0.0" + }, + "singleProjectMode": true, + "storage": { + "port": 9199 + } + }, + "storage": { + "rules": "storage.rules" + } +} diff --git a/firebase-emulator/firestore.indexes.json b/firebase-emulator/firestore.indexes.json new file mode 100644 index 000000000..415027e5d --- /dev/null +++ b/firebase-emulator/firestore.indexes.json @@ -0,0 +1,4 @@ +{ + "indexes": [], + "fieldOverrides": [] +} diff --git a/firebase-emulator/firestore.rules b/firebase-emulator/firestore.rules new file mode 100644 index 000000000..c4f081d4b --- /dev/null +++ b/firebase-emulator/firestore.rules @@ -0,0 +1,9 @@ +rules_version = '2'; +service cloud.firestore { + match /databases/{database}/documents { + match /{document=**} { + allow read, write: if + request.time < timestamp.date(2025, 10, 18); + } + } +} \ No newline at end of file diff --git a/firebase-emulator/storage.rules b/firebase-emulator/storage.rules new file mode 100644 index 000000000..c807920e6 --- /dev/null +++ b/firebase-emulator/storage.rules @@ -0,0 +1,12 @@ +rules_version = '2'; + +// Craft rules based on data in your Firestore database +// allow write: if firestore.get( +// /databases/(default)/documents/users/$(request.auth.uid)).data.isAdmin; +service firebase.storage { + match /b/{bucket}/o { + match /{allPaths=**} { + allow read, write: if true; + } + } +} From 20162516efc7579b2dd6192f437f60ce3356d893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 14:31:49 +0200 Subject: [PATCH 28/78] update playwright action --- .github/workflows/playwright.yml | 48 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 41abbf27d..71e175d96 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -3,29 +3,29 @@ name: Playwright Tests on: [push, pull_request] jobs: - test: - timeout-minutes: 60 + setup: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - - name: Install dependencies - run: npm ci - - name: Install Playwright Browsers - run: npx playwright install --with-deps - - name: Run Playwright tests - run: npx playwright test - - uses: actions/upload-artifact@v4 - if: ${{ !cancelled() }} - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: playwright-screenshots - path: playwright/output - retention-days: 30 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Start Docker Compose + run: docker-compose up -d + + - name: Wait for services to start + run: | + timeout=300 + until curl -sSf http://localhost:4321 -o /dev/null; do + timeout=$(($timeout - 1)) + if [ $timeout -eq 0 ]; then + echo "Services did not start in time" + exit 1 + fi + sleep 1 + done + + - name: Run Playwright tests + run: npx playwright test + + - name: Stop Docker Compose + run: docker-compose down From 36edaee24adaf56daac9a74ab3560a4510395b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 14:33:15 +0200 Subject: [PATCH 29/78] test remove .env dockercompose --- docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c4f21fd46..fc34c6823 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,6 @@ services: dockerfile: Dockerfile ports: - "4321:5000" - env_file: - - .env depends_on: - firebase-emulator From c32f623707c1517ed0a6cfcd1328543bef4777b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 14:47:17 +0200 Subject: [PATCH 30/78] test github action --- .github/workflows/playwright.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 71e175d96..00263d7b0 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -24,6 +24,9 @@ jobs: sleep 1 done + - name: Print index page + run: curl http://localhost:4321 + - name: Run Playwright tests run: npx playwright test From dbb7d8621e4b3c6946301830995ea20a243f6db2 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 14:25:02 +0200 Subject: [PATCH 31/78] Added testing for development --- playwright.config.js | 42 +++++++++++++++++++++++++++----- playwright/output/.last-run.json | 4 +++ 2 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 playwright/output/.last-run.json diff --git a/playwright.config.js b/playwright.config.js index a7e77f982..8ea55662c 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -31,18 +31,48 @@ module.exports = defineConfig({ /* Configure projects for major browsers */ projects: [ { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + name: 'chromium-dev', + use: { + baseURL: 'https://ruxailab-dev.web.app/', + ...devices['Desktop Chrome'], + }, + }, + { + name: 'chromium-prod', + use: { + baseURL: 'https://ruxailab-prod.web.app/', + ...devices['Desktop Chrome'], + }, }, { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, + name: 'firefox-dev', + use: { + baseURL: 'https://ruxailab-dev.web.app/', + ...devices['Desktop Firefox'], + }, + }, + { + name: 'firefox-prod', + use: { + baseURL: 'https://ruxailab-prod.web.app/', + ...devices['Desktop Firefox'], + }, }, { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, + name: 'webkit-dev', + use: { + baseURL: 'https://ruxailab-dev.web.app/', + ...devices['Desktop Safari'], + }, + }, + { + name: 'webkit-prod', + use: { + baseURL: 'https://ruxailab-prod.web.app/', + ...devices['Desktop Safari'], + }, }, ], }) diff --git a/playwright/output/.last-run.json b/playwright/output/.last-run.json new file mode 100644 index 000000000..cbcc1fbac --- /dev/null +++ b/playwright/output/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file From 8ba29ede3b7e3ad0c708d334767aaa729c50c1cd Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 14:25:56 +0200 Subject: [PATCH 32/78] Setup deifferent number of retries for dev and prod --- playwright.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/playwright.config.js b/playwright.config.js index 8ea55662c..534c30147 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -36,6 +36,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app/', ...devices['Desktop Chrome'], }, + retries: 2, }, { name: 'chromium-prod', @@ -43,6 +44,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-prod.web.app/', ...devices['Desktop Chrome'], }, + retries: 0, }, { @@ -51,6 +53,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app/', ...devices['Desktop Firefox'], }, + retries: 2, }, { name: 'firefox-prod', @@ -58,6 +61,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-prod.web.app/', ...devices['Desktop Firefox'], }, + retries: 0, }, { @@ -66,6 +70,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app/', ...devices['Desktop Safari'], }, + retries: 2, }, { name: 'webkit-prod', @@ -73,6 +78,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-prod.web.app/', ...devices['Desktop Safari'], }, + retries: 0, }, ], }) From 0e5c64807b753556dcea809110ff23eacb6b23db Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 14:26:23 +0200 Subject: [PATCH 33/78] Added video recording on first rety --- playwright.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/playwright.config.js b/playwright.config.js index 534c30147..2afc216a3 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -26,6 +26,8 @@ module.exports = defineConfig({ /* Create a screenshot if a test fails */ screenshot: { mode: 'only-on-failure', fullPage: true }, + + video: { mode: 'on-first-retry' }, }, /* Configure projects for major browsers */ From b1c66e9301065b787801ba92269c0212fa36bae7 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 14:34:36 +0200 Subject: [PATCH 34/78] Using the base url variable in the playwright tests --- .gitignore | 3 +++ e2e/ruxailabtest.spec.js | 4 ++-- playwright.config.js | 13 +++++++------ playwright/output/.last-run.json | 14 ++++++++++++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index ded603bf3..ed46891a5 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ firebase-debug.log /playwright-report/ /blob-report/ /playwright/.cache/ + +# Ignore the playwright test screenshots and video +/playwright/output \ No newline at end of file diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 9c5464294..6b49713f9 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -2,7 +2,7 @@ const { test, expect } = require('@playwright/test') const { log } = require('console') const logIn = async (page) => { - await page.goto('https://ruxailab-prod.web.app/signin') + await page.goto('/signin') await page.getByLabel('E-mail').fill('testemail@gmail.com') await page.getByLabel('Password', { exact: true }).fill('password123') @@ -42,7 +42,7 @@ const createTest = async (page, type) => { } test('has link page', async ({ page }) => { - await page.goto('https://ruxailab-prod.web.app/') + await page.goto('/') // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/RUXAILAB/) diff --git a/playwright.config.js b/playwright.config.js index 2afc216a3..98208e15a 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -27,6 +27,7 @@ module.exports = defineConfig({ /* Create a screenshot if a test fails */ screenshot: { mode: 'only-on-failure', fullPage: true }, + // Records video on first retry after fail video: { mode: 'on-first-retry' }, }, @@ -35,7 +36,7 @@ module.exports = defineConfig({ { name: 'chromium-dev', use: { - baseURL: 'https://ruxailab-dev.web.app/', + baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Chrome'], }, retries: 2, @@ -43,7 +44,7 @@ module.exports = defineConfig({ { name: 'chromium-prod', use: { - baseURL: 'https://ruxailab-prod.web.app/', + baseURL: 'https://ruxailab-prod.web.app', ...devices['Desktop Chrome'], }, retries: 0, @@ -52,7 +53,7 @@ module.exports = defineConfig({ { name: 'firefox-dev', use: { - baseURL: 'https://ruxailab-dev.web.app/', + baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Firefox'], }, retries: 2, @@ -60,7 +61,7 @@ module.exports = defineConfig({ { name: 'firefox-prod', use: { - baseURL: 'https://ruxailab-prod.web.app/', + baseURL: 'https://ruxailab-prod.web.app', ...devices['Desktop Firefox'], }, retries: 0, @@ -69,7 +70,7 @@ module.exports = defineConfig({ { name: 'webkit-dev', use: { - baseURL: 'https://ruxailab-dev.web.app/', + baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Safari'], }, retries: 2, @@ -77,7 +78,7 @@ module.exports = defineConfig({ { name: 'webkit-prod', use: { - baseURL: 'https://ruxailab-prod.web.app/', + baseURL: 'https://ruxailab-prod.web.app', ...devices['Desktop Safari'], }, retries: 0, diff --git a/playwright/output/.last-run.json b/playwright/output/.last-run.json index cbcc1fbac..9c128f33c 100644 --- a/playwright/output/.last-run.json +++ b/playwright/output/.last-run.json @@ -1,4 +1,14 @@ { - "status": "passed", - "failedTests": [] + "status": "failed", + "failedTests": [ + "7614e67dcde585484869-809ac754bc77e52e4a95", + "7614e67dcde585484869-8563de2c73e28f66c2ff", + "7614e67dcde585484869-34bc1220149fffc97d0b", + "7614e67dcde585484869-c421f1bdea8490924116", + "7614e67dcde585484869-9f25dc33418514581af2", + "7614e67dcde585484869-dd7dc9bf3c15843014dc", + "7614e67dcde585484869-8cb794136db1eaa07069", + "7614e67dcde585484869-4587b36b692dea8a3c6e", + "7614e67dcde585484869-ac7b911041e54edd8570" + ] } \ No newline at end of file From d38a26b18cea259e540dd7f9837f277e1c4545c6 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 15:32:10 +0200 Subject: [PATCH 35/78] Finished up the test configuration --- playwright.config.js | 8 ++++---- playwright/output/.last-run.json | 14 -------------- 2 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 playwright/output/.last-run.json diff --git a/playwright.config.js b/playwright.config.js index 98208e15a..e6d79b6c6 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -28,7 +28,7 @@ module.exports = defineConfig({ screenshot: { mode: 'only-on-failure', fullPage: true }, // Records video on first retry after fail - video: { mode: 'on-first-retry' }, + video: 'on-first-retry', }, /* Configure projects for major browsers */ @@ -39,7 +39,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Chrome'], }, - retries: 2, + retries: 1, }, { name: 'chromium-prod', @@ -56,7 +56,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Firefox'], }, - retries: 2, + retries: 1, }, { name: 'firefox-prod', @@ -73,7 +73,7 @@ module.exports = defineConfig({ baseURL: 'https://ruxailab-dev.web.app', ...devices['Desktop Safari'], }, - retries: 2, + retries: 1, }, { name: 'webkit-prod', diff --git a/playwright/output/.last-run.json b/playwright/output/.last-run.json deleted file mode 100644 index 9c128f33c..000000000 --- a/playwright/output/.last-run.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "status": "failed", - "failedTests": [ - "7614e67dcde585484869-809ac754bc77e52e4a95", - "7614e67dcde585484869-8563de2c73e28f66c2ff", - "7614e67dcde585484869-34bc1220149fffc97d0b", - "7614e67dcde585484869-c421f1bdea8490924116", - "7614e67dcde585484869-9f25dc33418514581af2", - "7614e67dcde585484869-dd7dc9bf3c15843014dc", - "7614e67dcde585484869-8cb794136db1eaa07069", - "7614e67dcde585484869-4587b36b692dea8a3c6e", - "7614e67dcde585484869-ac7b911041e54edd8570" - ] -} \ No newline at end of file From a78d5b38ab8f462468d06ef75ad699aaad2ed4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:03:37 +0200 Subject: [PATCH 36/78] actualizar dockerfile --- Dockerfile-playwright | 38 ++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 2 +- e2e/ruxailabtest.spec.js | 4 ++-- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 Dockerfile-playwright diff --git a/Dockerfile-playwright b/Dockerfile-playwright new file mode 100644 index 000000000..d406d65d6 --- /dev/null +++ b/Dockerfile-playwright @@ -0,0 +1,38 @@ +# Etapa 1: Construcción +FROM node:lts AS build-stage + +WORKDIR /app + +# Copiar y instalar dependencias +COPY package*.json ./ +RUN npm install + +# Copiar el resto de la aplicación y construir +COPY . . +RUN npm run build-dev + +# Etapa 2: Producción y Pruebas +FROM node:18 + +WORKDIR /app + +# Instalar 'serve' y 'wait-on' para servir la aplicación y esperar a que esté lista +RUN npm install -g serve wait-on + +# Copiar la aplicación construida desde la etapa de construcción +COPY --from=build-stage /app/dist /app + +# Copiar y instalar dependencias necesarias para Playwright +COPY package*.json ./ +RUN npx playwright install --with-deps +RUN npm install @playwright/test -D + +# Copiar la configuración de Playwright y el resto de la aplicación +COPY playwright.config.js . +COPY . . + +# Exponer el puerto en el que se servirá la aplicación +EXPOSE 5000 + +# Ejecutar la aplicación y esperar a que esté disponible antes de ejecutar las pruebas +CMD ["sh", "-c", "serve -s . -l 5000 & wait-on http://localhost:5000 && npx playwright test"] diff --git a/docker-compose.yml b/docker-compose.yml index fc34c6823..397c467a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: uxremotelab: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile-playwright ports: - "4321:5000" depends_on: diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 6b49713f9..41a1a031d 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -2,7 +2,7 @@ const { test, expect } = require('@playwright/test') const { log } = require('console') const logIn = async (page) => { - await page.goto('/signin') + await page.goto('http://localhost:5000/signin') await page.getByLabel('E-mail').fill('testemail@gmail.com') await page.getByLabel('Password', { exact: true }).fill('password123') @@ -42,7 +42,7 @@ const createTest = async (page, type) => { } test('has link page', async ({ page }) => { - await page.goto('/') + await page.goto('http://localhost:5000/') // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/RUXAILAB/) From d6d4e76840def80fcd70413480a7c7382ff226d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:15:03 +0200 Subject: [PATCH 37/78] test action --- .github/workflows/playwright.yml | 52 +++++++++++++++++++------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 00263d7b0..c775ba901 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -3,32 +3,42 @@ name: Playwright Tests on: [push, pull_request] jobs: - setup: + build: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - - name: Start Docker Compose - run: docker-compose up -d + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 - - name: Wait for services to start + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '18.x' # Cambia esto a la versión de Node.js que usas + + - name: Build and start services + run: | + docker-compose up -d --build + + - name: Wait for services to be ready run: | - timeout=300 - until curl -sSf http://localhost:4321 -o /dev/null; do - timeout=$(($timeout - 1)) - if [ $timeout -eq 0 ]; then - echo "Services did not start in time" - exit 1 - fi - sleep 1 - done - - - name: Print index page - run: curl http://localhost:4321 + while ! nc -z localhost 4321; do sleep 10; done + while ! nc -z localhost 5001; do sleep 10; done - name: Run Playwright tests - run: npx playwright test + run: | + npm ci + npx playwright install-deps + npx playwright test - - name: Stop Docker Compose - run: docker-compose down + - name: Stop services + run: | + docker-compose down From cf9c0056b9234aaaee4552560c7f19324ad44563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:19:01 +0200 Subject: [PATCH 38/78] cambiar docker compose file --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 397c467a2..fc34c6823 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: uxremotelab: build: context: . - dockerfile: Dockerfile-playwright + dockerfile: Dockerfile ports: - "4321:5000" depends_on: From e4ff2e4c4b325f93aa92dc68ce41aa3bb24cc449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:22:01 +0200 Subject: [PATCH 39/78] change actions --- .github/workflows/playwright.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c775ba901..898df3c7f 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -31,12 +31,12 @@ jobs: - name: Wait for services to be ready run: | while ! nc -z localhost 4321; do sleep 10; done - while ! nc -z localhost 5001; do sleep 10; done + while ! nc -z localhost 4000; do sleep 10; done - name: Run Playwright tests run: | npm ci - npx playwright install-deps + npx playwright install npx playwright test - name: Stop services From f3cdc4202f1059423daa5aeec468a0de9cebecc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:30:32 +0200 Subject: [PATCH 40/78] change port --- .github/workflows/playwright.yml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 898df3c7f..cf98b4013 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,7 @@ jobs: - name: Wait for services to be ready run: | - while ! nc -z localhost 4321; do sleep 10; done + while ! nc -z localhost 5000; do sleep 10; done while ! nc -z localhost 4000; do sleep 10; done - name: Run Playwright tests diff --git a/docker-compose.yml b/docker-compose.yml index fc34c6823..c1ecdc065 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: context: . dockerfile: Dockerfile ports: - - "4321:5000" + - "5000:5000" depends_on: - firebase-emulator From b277875636ccf27e0d9f749989f8f0786ea66ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:42:33 +0200 Subject: [PATCH 41/78] change action playwright --- .github/workflows/playwright.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index cf98b4013..bbe60cd74 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,13 @@ jobs: run: | npm ci npx playwright install - npx playwright test + npx playwright test --project webkit + - uses: actions/upload-artifact@v2 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 - name: Stop services run: | From 74e4accfc4d887933150ef31b57e1ecbf2fd0509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 16:46:44 +0200 Subject: [PATCH 42/78] change action playwright --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index bbe60cd74..d2e705d75 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: run: | npm ci npx playwright install - npx playwright test --project webkit + npx playwright test --project chromium-dev - uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} with: From bded608214fe95890ad6e145a947af9be4de73fe Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 18:35:34 +0200 Subject: [PATCH 43/78] Added more UI tests Added more UI tests and resolved conflicts --- e2e/ruxailabtest.spec.js | 92 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 41a1a031d..2efb9d6f1 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -42,7 +42,7 @@ const createTest = async (page, type) => { } test('has link page', async ({ page }) => { - await page.goto('http://localhost:5000/') + await page.goto('/') // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/RUXAILAB/) @@ -84,3 +84,93 @@ test('sign and create template', async ({ page }) => { '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', ) // Click go back to console button }) + +test('failure test heuristic', async ({ page }) => { + await logIn(page) + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + await page.click('.card-title:has-text("Create a blank test")') + await page.click('.card.col-sm-10.col-md-5.col-12') + await page + .getByRole('textbox', { name: 'Test Description' }) + .fill('Some descripton') + await page.click( + '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', + ) + + const errorMessage = page.locator('div[role="alert"]') + await expect(errorMessage).toBeVisible() + await expect(errorMessage).toHaveText('Enter a Title') +}) + +test('Detalte test', async ({ page }) => { + await logIn(page) + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + + await page.click('.card-title:has-text("Create a blank test")') + await page.click('.card.col-sm-10.col-md-5.col-12') + + await page + .getByRole('textbox', { name: 'Test Name' }) + .fill('Test heuristic playwright for delate') + await page + .getByRole('textbox', { name: 'Test Description' }) + .fill('Some descripton') + + await page.click( + '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', + ) + await page.click('.card.col-sm-10.col-md-4.col-10') + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) + + await page.goto('https://ruxailab-prod.web.app/testslist') + + await page.click('text=Test heuristic playwright for delate') + await page.click( + '.v-btn.v-btn--icon.v-btn--round.theme--light.v-size--default', + ) + await page.click( + '.white--text.mb-4.v-btn.v-btn--is-elevated.v-btn--has-bg.theme--light.v-size--default', + ) + await page.click( + '.red.white--text.ml-1.v-btn.v-btn--text.theme--light.v-size--default', + ) +}) + +test('failure test template', async ({ page }) => { + logIn(page) + + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) + await page.click('.card-title:has-text("Create from template")') + + await page.click('.v-list-item.v-list-item--link.theme--light') + await page.getByRole('button', { name: 'NEXT' }).click() + await page.getByRole('textbox', { name: 'Title' }).fill('') + await page + .getByRole('textbox', { name: 'Description' }) + .fill('Some description for template') + await page.getByRole('button', { name: 'CREATE' }).click() + + try { + await page.waitForSelector( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + { timeout: 5000 }, + ) + await expect(page).toHaveURL('https://ruxailab-prod.web.app/testslist') + } catch { + console.error('Failed to click button or URL did not match:') + page.close() + } +}) From 5f1f8f56dc9879a18ee7c61604c63b8bb3cc58f2 Mon Sep 17 00:00:00 2001 From: zlatanjakic Date: Sun, 2 Jun 2024 18:45:17 +0200 Subject: [PATCH 44/78] Parametrized base url for all tests --- e2e/ruxailabtest.spec.js | 4 ++-- playwright.config.js | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 2efb9d6f1..ac540738a 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -2,7 +2,7 @@ const { test, expect } = require('@playwright/test') const { log } = require('console') const logIn = async (page) => { - await page.goto('http://localhost:5000/signin') + await page.goto('/signin') await page.getByLabel('E-mail').fill('testemail@gmail.com') await page.getByLabel('Password', { exact: true }).fill('password123') @@ -130,7 +130,7 @@ test('Detalte test', async ({ page }) => { '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', ) - await page.goto('https://ruxailab-prod.web.app/testslist') + await page.goto('/testslist') await page.click('text=Test heuristic playwright for delate') await page.click( diff --git a/playwright.config.js b/playwright.config.js index e6d79b6c6..5e02a16bd 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,6 +1,9 @@ // @ts-check const { defineConfig, devices } = require('@playwright/test') +const devBaseUrl = 'http://localhost:5000' +const prodBaseUrl = 'https://ruxailab-prod.web.app' + module.exports = defineConfig({ testDir: './e2e', /* Run tests in files in parallel */ @@ -36,7 +39,7 @@ module.exports = defineConfig({ { name: 'chromium-dev', use: { - baseURL: 'https://ruxailab-dev.web.app', + baseURL: devBaseUrl, ...devices['Desktop Chrome'], }, retries: 1, @@ -44,7 +47,7 @@ module.exports = defineConfig({ { name: 'chromium-prod', use: { - baseURL: 'https://ruxailab-prod.web.app', + baseURL: prodBaseUrl, ...devices['Desktop Chrome'], }, retries: 0, @@ -53,7 +56,7 @@ module.exports = defineConfig({ { name: 'firefox-dev', use: { - baseURL: 'https://ruxailab-dev.web.app', + baseURL: devBaseUrl, ...devices['Desktop Firefox'], }, retries: 1, @@ -61,7 +64,7 @@ module.exports = defineConfig({ { name: 'firefox-prod', use: { - baseURL: 'https://ruxailab-prod.web.app', + baseURL: prodBaseUrl, ...devices['Desktop Firefox'], }, retries: 0, @@ -70,13 +73,13 @@ module.exports = defineConfig({ { name: 'webkit-dev', use: { - baseURL: 'https://ruxailab-dev.web.app', + baseURL: devBaseUrl, ...devices['Desktop Safari'], }, retries: 1, }, { - name: 'webkit-prod', + name: prodBaseUrl, use: { baseURL: 'https://ruxailab-prod.web.app', ...devices['Desktop Safari'], From 8e455175ef400b7840d1be7af3cd22f7baea906d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 20:28:56 +0200 Subject: [PATCH 45/78] change playwright action --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d2e705d75..539068028 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: run: | npm ci npx playwright install - npx playwright test --project chromium-dev + npx playwright test --project firefox - uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} with: From 9c26cb385c0e74d5a38222b319b6f2d7d02f3d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 20:36:43 +0200 Subject: [PATCH 46/78] change playwright action --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 539068028..db78444e7 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: run: | npm ci npx playwright install - npx playwright test --project firefox + npx playwright test --project webkit-dev - uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} with: From e4cd450ad03d7fb58d2156410e041134a02f293a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 20:49:27 +0200 Subject: [PATCH 47/78] change playwright testing --- .github/workflows/playwright.yml | 2 +- playwright.config.js | 53 +++----------------------------- 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index db78444e7..13bc51a3c 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: run: | npm ci npx playwright install - npx playwright test --project webkit-dev + npx playwright test - uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} with: diff --git a/playwright.config.js b/playwright.config.js index 5e02a16bd..54e2fdc1f 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -2,7 +2,6 @@ const { defineConfig, devices } = require('@playwright/test') const devBaseUrl = 'http://localhost:5000' -const prodBaseUrl = 'https://ruxailab-prod.web.app' module.exports = defineConfig({ testDir: './e2e', @@ -19,7 +18,10 @@ module.exports = defineConfig({ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', + reporter: [ + ['list'], + ['@estruyf/github-actions-reporter'] + ] /* Output directory for screenshots of failed tests */ outputDir: './playwright/output', @@ -29,62 +31,17 @@ module.exports = defineConfig({ /* Create a screenshot if a test fails */ screenshot: { mode: 'only-on-failure', fullPage: true }, - - // Records video on first retry after fail - video: 'on-first-retry', }, /* Configure projects for major browsers */ projects: [ { - name: 'chromium-dev', + name: 'chromium', use: { baseURL: devBaseUrl, ...devices['Desktop Chrome'], }, retries: 1, }, - { - name: 'chromium-prod', - use: { - baseURL: prodBaseUrl, - ...devices['Desktop Chrome'], - }, - retries: 0, - }, - - { - name: 'firefox-dev', - use: { - baseURL: devBaseUrl, - ...devices['Desktop Firefox'], - }, - retries: 1, - }, - { - name: 'firefox-prod', - use: { - baseURL: prodBaseUrl, - ...devices['Desktop Firefox'], - }, - retries: 0, - }, - - { - name: 'webkit-dev', - use: { - baseURL: devBaseUrl, - ...devices['Desktop Safari'], - }, - retries: 1, - }, - { - name: prodBaseUrl, - use: { - baseURL: 'https://ruxailab-prod.web.app', - ...devices['Desktop Safari'], - }, - retries: 0, - }, ], }) From 72f2788807f4559ee781e6353a7dc34bc3d4b752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sun, 2 Jun 2024 20:53:30 +0200 Subject: [PATCH 48/78] solve error --- playwright.config.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/playwright.config.js b/playwright.config.js index 54e2fdc1f..f42de8475 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -18,10 +18,7 @@ module.exports = defineConfig({ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [ - ['list'], - ['@estruyf/github-actions-reporter'] - ] + reporter: [['list'], ['@estruyf/github-actions-reporter']], /* Output directory for screenshots of failed tests */ outputDir: './playwright/output', From a22013f0de392488f279610d558cf2def9c3fe71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:23:58 +0200 Subject: [PATCH 49/78] change playwright --- playwright.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playwright.config.js b/playwright.config.js index f42de8475..440322997 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -18,11 +18,12 @@ module.exports = defineConfig({ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [['list'], ['@estruyf/github-actions-reporter']], + reporter: 'html', /* Output directory for screenshots of failed tests */ outputDir: './playwright/output', use: { + ...devices['Desktop Chrome'], /* Collect trace when retrying the failed test */ trace: 'on-first-retry', From 2acab047479019123d5540f192f8d4ad37425ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:33:20 +0200 Subject: [PATCH 50/78] comment all test to test github action --- e2e/ruxailabtest.spec.js | 352 +++++++++++++++++++-------------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index ac540738a..efec65cd8 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -1,176 +1,176 @@ -const { test, expect } = require('@playwright/test') -const { log } = require('console') - -const logIn = async (page) => { - await page.goto('/signin') - - await page.getByLabel('E-mail').fill('testemail@gmail.com') - await page.getByLabel('Password', { exact: true }).fill('password123') - - await page - .getByRole('main') - .getByRole('button', { name: 'Sign-In' }) - .click() -} - -const createTest = async (page, type) => { - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) // Click new test button - - await page.click('.card-title:has-text("Create a blank test")') - - type === 'heuristic' && (await page.click('.card.col-sm-10.col-md-5.col-10')) // Press heuristic test card - type === 'usability' && (await page.click('.card.col-sm-10.col-md-5.col-12')) // Press usability test card - - await page - .getByRole('textbox', { name: 'Test Name' }) - .fill('Test heuristic playwright') - await page - .getByRole('textbox', { name: 'Test Description' }) - .fill('Some descripton') - - await page.click( - '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', - ) // Click create test button - - type === 'usability' && (await page.click('.card.col-sm-10.col-md-4.col-10')) // Click self test card - - await page.click( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) // Click go back to console button -} - -test('has link page', async ({ page }) => { - await page.goto('/') - - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/RUXAILAB/) -}) - -test('sign and create heurisic test', async ({ page }) => { - await logIn(page) - - await createTest(page, 'heuristic') -}) - -test('sign and create usability test', async ({ page }) => { - await logIn(page) - - await createTest(page, 'usability') -}) - -test('sign and create template', async ({ page }) => { - /*login*/ - await logIn(page) - - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) // Click create new test button - await page.click('.card-title:has-text("Create from template")') - - //create MARCTEST - await page.click('.v-list-item.v-list-item--link.theme--light') // Select template - await page.getByRole('button', { name: 'NEXT' }).click() - await page - .getByRole('textbox', { name: 'Title' }) - .fill('Test template playwrigth') - await page - .getByRole('textbox', { name: 'Description' }) - .fill('Some description for template') - await page.getByRole('button', { name: 'CREATE' }).click() - - await page.click( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) // Click go back to console button -}) - -test('failure test heuristic', async ({ page }) => { - await logIn(page) - - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - await page.click('.card-title:has-text("Create a blank test")') - await page.click('.card.col-sm-10.col-md-5.col-12') - await page - .getByRole('textbox', { name: 'Test Description' }) - .fill('Some descripton') - await page.click( - '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', - ) - - const errorMessage = page.locator('div[role="alert"]') - await expect(errorMessage).toBeVisible() - await expect(errorMessage).toHaveText('Enter a Title') -}) - -test('Detalte test', async ({ page }) => { - await logIn(page) - - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - - await page.click('.card-title:has-text("Create a blank test")') - await page.click('.card.col-sm-10.col-md-5.col-12') - - await page - .getByRole('textbox', { name: 'Test Name' }) - .fill('Test heuristic playwright for delate') - await page - .getByRole('textbox', { name: 'Test Description' }) - .fill('Some descripton') - - await page.click( - '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', - ) - await page.click('.card.col-sm-10.col-md-4.col-10') - await page.click( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) - - await page.goto('/testslist') - - await page.click('text=Test heuristic playwright for delate') - await page.click( - '.v-btn.v-btn--icon.v-btn--round.theme--light.v-size--default', - ) - await page.click( - '.white--text.mb-4.v-btn.v-btn--is-elevated.v-btn--has-bg.theme--light.v-size--default', - ) - await page.click( - '.red.white--text.ml-1.v-btn.v-btn--text.theme--light.v-size--default', - ) -}) - -test('failure test template', async ({ page }) => { - logIn(page) - - await page.click( - 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', - ) - await page.click('.card-title:has-text("Create from template")') - - await page.click('.v-list-item.v-list-item--link.theme--light') - await page.getByRole('button', { name: 'NEXT' }).click() - await page.getByRole('textbox', { name: 'Title' }).fill('') - await page - .getByRole('textbox', { name: 'Description' }) - .fill('Some description for template') - await page.getByRole('button', { name: 'CREATE' }).click() - - try { - await page.waitForSelector( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - ) - await page.click( - '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', - { timeout: 5000 }, - ) - await expect(page).toHaveURL('https://ruxailab-prod.web.app/testslist') - } catch { - console.error('Failed to click button or URL did not match:') - page.close() - } -}) +const { test, expect } = require('@playwright/test') +const { log } = require('console') + +const logIn = async (page) => { + await page.goto('/signin') + + await page.getByLabel('E-mail').fill('testemail@gmail.com') + await page.getByLabel('Password', { exact: true }).fill('password123') + + await page + .getByRole('main') + .getByRole('button', { name: 'Sign-In' }) + .click() +} + +const createTest = async (page, type) => { + await page.click( + 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', + ) // Click new test button + + await page.click('.card-title:has-text("Create a blank test")') + + type === 'heuristic' && (await page.click('.card.col-sm-10.col-md-5.col-10')) // Press heuristic test card + type === 'usability' && (await page.click('.card.col-sm-10.col-md-5.col-12')) // Press usability test card + + await page + .getByRole('textbox', { name: 'Test Name' }) + .fill('Test heuristic playwright') + await page + .getByRole('textbox', { name: 'Test Description' }) + .fill('Some descripton') + + await page.click( + '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', + ) // Click create test button + + type === 'usability' && (await page.click('.card.col-sm-10.col-md-4.col-10')) // Click self test card + + await page.click( + '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', + ) // Click go back to console button +} + +test('has link page', async ({ page }) => { + await page.goto('/') + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/RUXAILAB/) +}) + +// test('sign and create heurisic test', async ({ page }) => { +// await logIn(page) + +// await createTest(page, 'heuristic') +// }) + +// test('sign and create usability test', async ({ page }) => { +// await logIn(page) + +// await createTest(page, 'usability') +// }) + +// test('sign and create template', async ({ page }) => { +// /*login*/ +// await logIn(page) + +// await page.click( +// 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', +// ) // Click create new test button +// await page.click('.card-title:has-text("Create from template")') + +// //create MARCTEST +// await page.click('.v-list-item.v-list-item--link.theme--light') // Select template +// await page.getByRole('button', { name: 'NEXT' }).click() +// await page +// .getByRole('textbox', { name: 'Title' }) +// .fill('Test template playwrigth') +// await page +// .getByRole('textbox', { name: 'Description' }) +// .fill('Some description for template') +// await page.getByRole('button', { name: 'CREATE' }).click() + +// await page.click( +// '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', +// ) // Click go back to console button +// }) + +// test('failure test heuristic', async ({ page }) => { +// await logIn(page) + +// await page.click( +// 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', +// ) +// await page.click('.card-title:has-text("Create a blank test")') +// await page.click('.card.col-sm-10.col-md-5.col-12') +// await page +// .getByRole('textbox', { name: 'Test Description' }) +// .fill('Some descripton') +// await page.click( +// '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', +// ) + +// const errorMessage = page.locator('div[role="alert"]') +// await expect(errorMessage).toBeVisible() +// await expect(errorMessage).toHaveText('Enter a Title') +// }) + +// test('Detalte test', async ({ page }) => { +// await logIn(page) + +// await page.click( +// 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', +// ) + +// await page.click('.card-title:has-text("Create a blank test")') +// await page.click('.card.col-sm-10.col-md-5.col-12') + +// await page +// .getByRole('textbox', { name: 'Test Name' }) +// .fill('Test heuristic playwright for delate') +// await page +// .getByRole('textbox', { name: 'Test Description' }) +// .fill('Some descripton') + +// await page.click( +// '.ml-auto.mr-2.circleOrange.v-btn.v-btn--fab.v-btn--has-bg.v-btn--round.theme--dark.v-size--default.orange', +// ) +// await page.click('.card.col-sm-10.col-md-4.col-10') +// await page.click( +// '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', +// ) + +// await page.goto('/testslist') + +// await page.click('text=Test heuristic playwright for delate') +// await page.click( +// '.v-btn.v-btn--icon.v-btn--round.theme--light.v-size--default', +// ) +// await page.click( +// '.white--text.mb-4.v-btn.v-btn--is-elevated.v-btn--has-bg.theme--light.v-size--default', +// ) +// await page.click( +// '.red.white--text.ml-1.v-btn.v-btn--text.theme--light.v-size--default', +// ) +// }) + +// test('failure test template', async ({ page }) => { +// logIn(page) + +// await page.click( +// 'button.v-btn.v-btn--bottom.v-btn--is-elevated.v-btn--fab.v-btn--fixed.v-btn--has-bg.v-btn--right.v-btn--round', +// ) +// await page.click('.card-title:has-text("Create from template")') + +// await page.click('.v-list-item.v-list-item--link.theme--light') +// await page.getByRole('button', { name: 'NEXT' }).click() +// await page.getByRole('textbox', { name: 'Title' }).fill('') +// await page +// .getByRole('textbox', { name: 'Description' }) +// .fill('Some description for template') +// await page.getByRole('button', { name: 'CREATE' }).click() + +// try { +// await page.waitForSelector( +// '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', +// ) +// await page.click( +// '.console-button.mx-1.hidden-sm-and-down.v-btn.v-btn--text.theme--dark.v-size--default', +// { timeout: 5000 }, +// ) +// await expect(page).toHaveURL('https://ruxailab-prod.web.app/testslist') +// } catch { +// console.error('Failed to click button or URL did not match:') +// page.close() +// } +// }) From 4c61cbeff4851ce1ac142b708241877fbfd964a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:35:17 +0200 Subject: [PATCH 51/78] test playwright action --- .github/workflows/playwright.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 13bc51a3c..a5d743dc8 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -33,10 +33,14 @@ jobs: while ! nc -z localhost 5000; do sleep 10; done while ! nc -z localhost 4000; do sleep 10; done + - name: Print Home page + run: | + curl http://localhost:5000 + - name: Run Playwright tests run: | npm ci - npx playwright install + npx playwright install --with-deps chromium npx playwright test - uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} From 33a33bb9974b136024076536c83dfc05902c3fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:41:01 +0200 Subject: [PATCH 52/78] change actions --- .github/workflows/playwright.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index a5d743dc8..d5e23a8b9 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -20,13 +20,12 @@ jobs: ${{ runner.os }}-buildx- - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: '18.x' # Cambia esto a la versión de Node.js que usas + node-version: '18.x' - name: Build and start services - run: | - docker-compose up -d --build + run: docker-compose up -d --build - name: Wait for services to be ready run: | @@ -34,15 +33,16 @@ jobs: while ! nc -z localhost 4000; do sleep 10; done - name: Print Home page - run: | - curl http://localhost:5000 + run: curl http://localhost:5000 - name: Run Playwright tests run: | npm ci npx playwright install --with-deps chromium npx playwright test - - uses: actions/upload-artifact@v2 + + - name: Upload Playwright report + uses: actions/upload-artifact@v2 if: ${{ !cancelled() }} with: name: playwright-report @@ -50,5 +50,4 @@ jobs: retention-days: 30 - name: Stop services - run: | - docker-compose down + run: docker-compose down From 548d6b6d8de9a66d750d5c6e30b7fb2a4b98434e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:45:55 +0200 Subject: [PATCH 53/78] include emulator in the project only in dev mode --- src/firebase/index.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/firebase/index.js b/src/firebase/index.js index 5bc3773f7..61004789f 100644 --- a/src/firebase/index.js +++ b/src/firebase/index.js @@ -2,19 +2,19 @@ import { initializeApp } from 'firebase/app' import { getAnalytics } from 'firebase/analytics' import { getAuth, - // connectAuthEmulator, + connectAuthEmulator, } from 'firebase/auth' import { getFirestore, - // connectFirestoreEmulator, + connectFirestoreEmulator, } from 'firebase/firestore' import { getFunctions, - // connectFunctionsEmulator + connectFunctionsEmulator, } from 'firebase/functions' import { getStorage, - // connectStorageEmulator + connectStorageEmulator, } from 'firebase/storage' const firebaseConfig = { @@ -34,9 +34,13 @@ const analytics = getAnalytics(firebaseApp) const fbFunctions = getFunctions(firebaseApp) const storage = getStorage(firebaseApp, `gs://${firebaseConfig.storageBucket}`) -// connectFirestoreEmulator(db, 'localhost', 8081) -// connectAuthEmulator(auth, 'http://localhost:9099') -// connectFunctionsEmulator(fbFunctions, 'localhost', 5001) -// connectStorageEmulator(storage, '127.0.0.1', 9199) +// Emulators if running locally + +if (process.env.NODE_ENV === 'development') { + connectFirestoreEmulator(db, 'localhost', 8081) + connectAuthEmulator(auth, 'http://localhost:9099') + connectFunctionsEmulator(fbFunctions, 'localhost', 5001) + connectStorageEmulator(storage, '127.0.0.1', 9199) +} export { auth, db, analytics, fbFunctions, storage } From 526b68694917d0542efa63988d011766a56ae7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:49:16 +0200 Subject: [PATCH 54/78] change port --- .github/workflows/playwright.yml | 4 ++-- docker-compose.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d5e23a8b9..c6854b628 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -29,11 +29,11 @@ jobs: - name: Wait for services to be ready run: | - while ! nc -z localhost 5000; do sleep 10; done + while ! nc -z localhost 4321; do sleep 10; done while ! nc -z localhost 4000; do sleep 10; done - name: Print Home page - run: curl http://localhost:5000 + run: curl http://localhost:4321/ - name: Run Playwright tests run: | diff --git a/docker-compose.yml b/docker-compose.yml index c1ecdc065..fc34c6823 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: context: . dockerfile: Dockerfile ports: - - "5000:5000" + - "4321:5000" depends_on: - firebase-emulator From 4ecfe6da87b6bde0fea9f3da46e7fad6697408f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:52:30 +0200 Subject: [PATCH 55/78] remove print --- .github/workflows/playwright.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c6854b628..68c5f4831 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -32,9 +32,6 @@ jobs: while ! nc -z localhost 4321; do sleep 10; done while ! nc -z localhost 4000; do sleep 10; done - - name: Print Home page - run: curl http://localhost:4321/ - - name: Run Playwright tests run: | npm ci From 55c474f1eb736ca164d4ce2546de89fa97f666cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 18:57:11 +0200 Subject: [PATCH 56/78] change port --- .github/workflows/playwright.yml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 68c5f4831..d1ea0087d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -29,7 +29,7 @@ jobs: - name: Wait for services to be ready run: | - while ! nc -z localhost 4321; do sleep 10; done + while ! nc -z localhost 5000; do sleep 10; done while ! nc -z localhost 4000; do sleep 10; done - name: Run Playwright tests diff --git a/docker-compose.yml b/docker-compose.yml index fc34c6823..c1ecdc065 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: context: . dockerfile: Dockerfile ports: - - "4321:5000" + - "5000:5000" depends_on: - firebase-emulator From 5cf7dd41bc2973c10ceced5699af84fe6fd75c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 19:44:53 +0200 Subject: [PATCH 57/78] change docker-compose --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index c1ecdc065..65edcbe04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: uxremotelab: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile-playwright ports: - "5000:5000" depends_on: From eb0300d2553cef40a562c85dce7f89910037d81d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 19:50:34 +0200 Subject: [PATCH 58/78] change action --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d1ea0087d..dca466b22 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -25,7 +25,7 @@ jobs: node-version: '18.x' - name: Build and start services - run: docker-compose up -d --build + run: docker-compose up -d --build -abort-on-container-exit --exit-code-from test - name: Wait for services to be ready run: | From 58dfb405efbfcb5abfc9fd05fc8f9f2253f25791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 19:52:38 +0200 Subject: [PATCH 59/78] change action --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index dca466b22..d1ea0087d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -25,7 +25,7 @@ jobs: node-version: '18.x' - name: Build and start services - run: docker-compose up -d --build -abort-on-container-exit --exit-code-from test + run: docker-compose up -d --build - name: Wait for services to be ready run: | From cfe43c8130d33194251af1572f3204ded52e8451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 20:01:39 +0200 Subject: [PATCH 60/78] new ci action --- .github/workflows/ci.yml | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..1a60e2d19 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build-and-test: + runs-on: ubuntu-latest + + services: + docker: + image: docker:19.03.12 + options: --privileged + ports: + - 5000:5000 + - 9099:9099 + - 5001:5001 + - 8081:8081 + - 5002:5002 + - 9199:9199 + - 4000:4000 + - 4400:4400 + - 4500:4500 + - 9150:9150 + - 5007:5007 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build and run Docker Compose + run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from test + + - name: Check Docker Compose Test Result + run: | + EXIT_CODE=$(docker inspect test --format='{{.State.ExitCode}}') + if [ "$EXIT_CODE" -ne 0 ]; then + exit $EXIT_CODE + fi From befd1e736db1ee8cb94d4e7d78ff3d4e4eab8c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 20:02:51 +0200 Subject: [PATCH 61/78] test ci --- .github/workflows/playwright.yml | 67 +++++++++++++++++--------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d1ea0087d..1a60e2d19 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,12 +1,37 @@ -name: Playwright Tests +name: CI -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: + branches: + - main jobs: - build: + build-and-test: runs-on: ubuntu-latest + + services: + docker: + image: docker:19.03.12 + options: --privileged + ports: + - 5000:5000 + - 9099:9099 + - 5001:5001 + - 8081:8081 + - 5002:5002 + - 9199:9199 + - 4000:4000 + - 4400:4400 + - 4500:4500 + - 9150:9150 + - 5007:5007 + steps: - - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 @@ -19,32 +44,12 @@ jobs: restore-keys: | ${{ runner.os }}-buildx- - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: '18.x' + - name: Build and run Docker Compose + run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from test - - name: Build and start services - run: docker-compose up -d --build - - - name: Wait for services to be ready + - name: Check Docker Compose Test Result run: | - while ! nc -z localhost 5000; do sleep 10; done - while ! nc -z localhost 4000; do sleep 10; done - - - name: Run Playwright tests - run: | - npm ci - npx playwright install --with-deps chromium - npx playwright test - - - name: Upload Playwright report - uses: actions/upload-artifact@v2 - if: ${{ !cancelled() }} - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 - - - name: Stop services - run: docker-compose down + EXIT_CODE=$(docker inspect test --format='{{.State.ExitCode}}') + if [ "$EXIT_CODE" -ne 0 ]; then + exit $EXIT_CODE + fi From 35ba9910d40b81409a2ab1656f2461666139a485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 20:04:05 +0200 Subject: [PATCH 62/78] change ci --- .github/workflows/ci.yml | 8 +--- .github/workflows/playwright.yml | 67 +++++++++++++++----------------- 2 files changed, 32 insertions(+), 43 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a60e2d19..ad719d723 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,6 @@ name: CI -on: - push: - branches: - - main - pull_request: - branches: - - main +on: [push, pull_request] jobs: build-and-test: diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 1a60e2d19..d1ea0087d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,37 +1,12 @@ -name: CI +name: Playwright Tests -on: - push: - branches: - - main - pull_request: - branches: - - main +on: [push, pull_request] jobs: - build-and-test: + build: runs-on: ubuntu-latest - - services: - docker: - image: docker:19.03.12 - options: --privileged - ports: - - 5000:5000 - - 9099:9099 - - 5001:5001 - - 8081:8081 - - 5002:5002 - - 9199:9199 - - 4000:4000 - - 4400:4400 - - 4500:4500 - - 9150:9150 - - 5007:5007 - steps: - - name: Checkout code - uses: actions/checkout@v2 + - uses: actions/checkout@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 @@ -44,12 +19,32 @@ jobs: restore-keys: | ${{ runner.os }}-buildx- - - name: Build and run Docker Compose - run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from test + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18.x' - - name: Check Docker Compose Test Result + - name: Build and start services + run: docker-compose up -d --build + + - name: Wait for services to be ready run: | - EXIT_CODE=$(docker inspect test --format='{{.State.ExitCode}}') - if [ "$EXIT_CODE" -ne 0 ]; then - exit $EXIT_CODE - fi + while ! nc -z localhost 5000; do sleep 10; done + while ! nc -z localhost 4000; do sleep 10; done + + - name: Run Playwright tests + run: | + npm ci + npx playwright install --with-deps chromium + npx playwright test + + - name: Upload Playwright report + uses: actions/upload-artifact@v2 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 + + - name: Stop services + run: docker-compose down From fe7f31e0522f9551afea00b8aac2bf91f376bacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 20:06:26 +0200 Subject: [PATCH 63/78] include test in docker compose --- docker-compose.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 65edcbe04..cd526d6a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,3 +29,18 @@ services: environment: - FIREBASE_PROJECT_ID=retlab-dev # Agrega cualquier otra variable de entorno necesaria para el emulador de Firebase + + test: + build: + context: . + volumes: + - .:/app + depends_on: + - uxremotelab + command: > + sh -c " + while ! curl -sSf localhost:5000 > /dev/null; do + echo 'Waiting for app...'; + sleep 2; + done; + npx playwright test" From 96a4a960bae171478261dbbe1a24dfc38dc2a155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Mon, 3 Jun 2024 20:12:50 +0200 Subject: [PATCH 64/78] change ci --- .github/workflows/ci.yml | 2 +- docker-compose.yml | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad719d723..bda9661ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: ${{ runner.os }}-buildx- - name: Build and run Docker Compose - run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from test + run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from uxremotelab - name: Check Docker Compose Test Result run: | diff --git a/docker-compose.yml b/docker-compose.yml index cd526d6a3..65edcbe04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,18 +29,3 @@ services: environment: - FIREBASE_PROJECT_ID=retlab-dev # Agrega cualquier otra variable de entorno necesaria para el emulador de Firebase - - test: - build: - context: . - volumes: - - .:/app - depends_on: - - uxremotelab - command: > - sh -c " - while ! curl -sSf localhost:5000 > /dev/null; do - echo 'Waiting for app...'; - sleep 2; - done; - npx playwright test" From db89d129c4141d7ad82b38e649bf2561c622d096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:21:04 +0200 Subject: [PATCH 65/78] test action --- .github/workflows/playwright.yml | 7 +++---- docker-compose.yml | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d1ea0087d..c5dd81ae3 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -27,10 +27,9 @@ jobs: - name: Build and start services run: docker-compose up -d --build - - name: Wait for services to be ready - run: | - while ! nc -z localhost 5000; do sleep 10; done - while ! nc -z localhost 4000; do sleep 10; done + - name: Wait for container to become available + run: npx wait-on http://localhost:8080 + timeout-minutes: 1 - name: Run Playwright tests run: | diff --git a/docker-compose.yml b/docker-compose.yml index 65edcbe04..71d40acf0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,9 +4,9 @@ services: uxremotelab: build: context: . - dockerfile: Dockerfile-playwright + dockerfile: Dockerfile ports: - - "5000:5000" + - "8080:5000" depends_on: - firebase-emulator From 94fa5c736fc091c129e1a0c89429336ea99a0979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:31:26 +0200 Subject: [PATCH 66/78] update action --- .github/workflows/playwright.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c5dd81ae3..73b14ee2a 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -31,19 +31,19 @@ jobs: run: npx wait-on http://localhost:8080 timeout-minutes: 1 + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps - name: Run Playwright tests - run: | - npm ci - npx playwright install --with-deps chromium - npx playwright test - - - name: Upload Playwright report - uses: actions/upload-artifact@v2 - if: ${{ !cancelled() }} + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: always() with: name: playwright-report path: playwright-report/ retention-days: 30 + - name: Stop services run: docker-compose down From f8db0f4e112704b28136ee01bc9f7a87dbca9690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:35:59 +0200 Subject: [PATCH 67/78] actualizar package json --- .github/workflows/ci.yml | 49 ---------- package-lock.json | 191 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 182 insertions(+), 58 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index bda9661ba..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - build-and-test: - runs-on: ubuntu-latest - - services: - docker: - image: docker:19.03.12 - options: --privileged - ports: - - 5000:5000 - - 9099:9099 - - 5001:5001 - - 8081:8081 - - 5002:5002 - - 9199:9199 - - 4000:4000 - - 4400:4400 - - 4500:4500 - - 9150:9150 - - 5007:5007 - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Build and run Docker Compose - run: docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from uxremotelab - - - name: Check Docker Compose Test Result - run: | - EXIT_CODE=$(docker inspect test --format='{{.State.ExitCode}}') - if [ "$EXIT_CODE" -ne 0 ]; then - exit $EXIT_CODE - fi diff --git a/package-lock.json b/package-lock.json index 2187cdac3..6234ee0f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "research-workflow", "version": "0.1.0", "dependencies": { + "@estruyf/github-actions-reporter": "^1.7.0", "axios": "^1.5.0", "bluebird": "^3.7.2", "caniuse-lite": "^1.0.30001534", @@ -67,6 +68,32 @@ "vuetify-loader": "^1.6.0" } }, + "node_modules/@actions/core": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", + "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", + "dependencies": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + } + }, + "node_modules/@actions/core/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz", + "integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, "node_modules/@adobe/css-tools": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", @@ -1331,6 +1358,34 @@ "ms": "^2.1.1" } }, + "node_modules/@estruyf/github-actions-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@estruyf/github-actions-reporter/-/github-actions-reporter-1.7.0.tgz", + "integrity": "sha512-Kucb/LNB9HnU4w1wIxiVyhcLajlT1p/Gs3yyNb4D/skz371Jy67dmq8pb3pL9SEGFXMxQVkHlQL5TegPux/9ag==", + "dependencies": { + "@actions/core": "^1.10.0", + "ansi-to-html": "^0.7.2", + "marked": "^12.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/estruyf" + }, + "peerDependencies": { + "@playwright/test": "^1.42.1" + } + }, + "node_modules/@estruyf/github-actions-reporter/node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/@fastify/busboy": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", @@ -4588,7 +4643,6 @@ "version": "1.44.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", - "dev": true, "dependencies": { "playwright": "1.44.1" }, @@ -6515,6 +6569,28 @@ "node": ">=4" } }, + "node_modules/ansi-to-html": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", + "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", + "dependencies": { + "entities": "^2.2.0" + }, + "bin": { + "ansi-to-html": "bin/ansi-to-html" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ansi-to-html/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/any-promise": { "version": "1.3.0", "dev": true, @@ -20125,7 +20201,6 @@ "version": "1.44.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", - "dev": true, "dependencies": { "playwright-core": "1.44.1" }, @@ -20143,7 +20218,6 @@ "version": "1.44.1", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", - "dev": true, "bin": { "playwright-core": "cli.js" }, @@ -20155,7 +20229,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -24135,6 +24208,14 @@ "version": "0.0.0", "license": "MIT" }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "dev": true, @@ -24274,11 +24355,30 @@ "underscore": "1.x" } }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/undici/node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "dev": true, @@ -26394,6 +26494,31 @@ } }, "dependencies": { + "@actions/core": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", + "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", + "requires": { + "@actions/http-client": "^2.0.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "@actions/http-client": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz", + "integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==", + "requires": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, "@adobe/css-tools": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", @@ -27335,6 +27460,23 @@ } } }, + "@estruyf/github-actions-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@estruyf/github-actions-reporter/-/github-actions-reporter-1.7.0.tgz", + "integrity": "sha512-Kucb/LNB9HnU4w1wIxiVyhcLajlT1p/Gs3yyNb4D/skz371Jy67dmq8pb3pL9SEGFXMxQVkHlQL5TegPux/9ag==", + "requires": { + "@actions/core": "^1.10.0", + "ansi-to-html": "^0.7.2", + "marked": "^12.0.1" + }, + "dependencies": { + "marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==" + } + } + }, "@fastify/busboy": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", @@ -30398,7 +30540,6 @@ "version": "1.44.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", - "dev": true, "requires": { "playwright": "1.44.1" } @@ -31861,6 +32002,21 @@ "color-convert": "^1.9.0" } }, + "ansi-to-html": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", + "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", + "requires": { + "entities": "^2.2.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, "any-promise": { "version": "1.3.0", "dev": true @@ -41880,7 +42036,6 @@ "version": "1.44.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", - "dev": true, "requires": { "fsevents": "2.3.2", "playwright-core": "1.44.1" @@ -41890,7 +42045,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true } } @@ -41898,8 +42052,7 @@ "playwright-core": { "version": "1.44.1", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", - "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", - "dev": true + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==" }, "pn": { "version": "1.1.0", @@ -44868,6 +45021,11 @@ "tty-browserify": { "version": "0.0.0" }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, "tunnel-agent": { "version": "0.6.0", "dev": true, @@ -44962,6 +45120,21 @@ "integrity": "sha512-4OuSOlFNkiVFVc3khkeG112Pdu1gbitMj7t9B9ENb61uFmN70Jq7Iluhi3oflcSgexkKfDdJ5XAJET2gEq6ikA==", "requires": {} }, + "undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "requires": { + "@fastify/busboy": "^2.0.0" + }, + "dependencies": { + "@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==" + } + } + }, "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", From 1165ea82a6b4722ef9d58e29f77c55cfa7c76470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:36:10 +0200 Subject: [PATCH 68/78] actualizar package json --- package.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1ed42ae8a..98636179d 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,14 @@ "build-prod": "vue-cli-service build --mode production", "cypress:open": "cypress open", "deploy-dev": "firebase use dev && firebase deploy --only hosting:ruxailab-dev", - "deploy-prod": "firebase use prod && firebase deploy --only hosting:ruxailab-prod" - }, + "deploy-prod": "firebase use prod && firebase deploy --only hosting:ruxailab-prod", + "test-playwright": "playwright test --browser=all", + "test-html-report": "playwright test --browser=all --reporter=html", + "test-json-report": "PLAYWRIGHT_JSON_OUTPUT_NAME=results.json playwright test --browser=chromium --reporter=json" + } +}, "dependencies": { + "@estruyf/github-actions-reporter": "^1.7.0", "axios": "^1.5.0", "bluebird": "^3.7.2", "caniuse-lite": "^1.0.30001534", From 21be287340efd8c6f34b4509922594438f83f418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:39:34 +0200 Subject: [PATCH 69/78] package json error --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 98636179d..af2ebc5e0 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,7 @@ "test-playwright": "playwright test --browser=all", "test-html-report": "playwright test --browser=all --reporter=html", "test-json-report": "PLAYWRIGHT_JSON_OUTPUT_NAME=results.json playwright test --browser=chromium --reporter=json" - } -}, + }, "dependencies": { "@estruyf/github-actions-reporter": "^1.7.0", "axios": "^1.5.0", From 872bb3a30868084146c89c6993d30b698437c9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:44:24 +0200 Subject: [PATCH 70/78] install dependencies --- .github/workflows/playwright.yml | 2 + package-lock.json | 231 ++++++++++++++++++++++++++++++- 2 files changed, 226 insertions(+), 7 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 73b14ee2a..199cbf594 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -31,6 +31,8 @@ jobs: run: npx wait-on http://localhost:8080 timeout-minutes: 1 + - name: Install npm dependencies + run: npm install - name: Install dependencies run: npm ci - name: Install Playwright Browsers diff --git a/package-lock.json b/package-lock.json index 6234ee0f0..13035a3a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "devDependencies": { "@intlify/vue-i18n-loader": "^1.1.0", "@playwright/test": "^1.44.1", + "@testing-library/cypress": "^10.0.1", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "12", @@ -56,7 +57,7 @@ "@vue/test-utils": "^1.3.0", "babel-eslint": "^8.2.6", "babel-plugin-transform-require-context": "^0.1.1", - "cypress": "^13.7.3", + "cypress": "^13.8.1", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "jsdoc": "^3.6.11", @@ -4810,6 +4811,121 @@ "dev": true, "license": "MIT" }, + "node_modules/@testing-library/cypress": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-10.0.2.tgz", + "integrity": "sha512-dKv95Bre5fDmNb9tOIuWedhGUryxGu1GWYWtXDqUsDPcr9Ekld0fiTb+pcBvSsFpYXAZSpmyEjhoXzLbhh06yQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.14.6", + "@testing-library/dom": "^10.1.0" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "cypress": "^12.0.0 || ^13.0.0" + } + }, + "node_modules/@testing-library/cypress/node_modules/@testing-library/dom": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", + "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/cypress/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/cypress/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/cypress/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/cypress/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/cypress/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/cypress/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -9749,9 +9865,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "13.7.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.3.tgz", - "integrity": "sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==", + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.10.0.tgz", + "integrity": "sha512-tOhwRlurVOQbMduX+KonoMeQILs2cwR3yHGGENoFvvSoLUBHmJ8b9/n21gFSDqjlOJ+SRVcwuh+fG/JDsHsT6Q==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -10653,6 +10769,15 @@ "node": ">= 0.6" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/des.js": { "version": "1.0.1", "license": "MIT", @@ -30654,6 +30779,92 @@ "version": "1.0.0", "dev": true }, + "@testing-library/cypress": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-10.0.2.tgz", + "integrity": "sha512-dKv95Bre5fDmNb9tOIuWedhGUryxGu1GWYWtXDqUsDPcr9Ekld0fiTb+pcBvSsFpYXAZSpmyEjhoXzLbhh06yQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.14.6", + "@testing-library/dom": "^10.1.0" + }, + "dependencies": { + "@testing-library/dom": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", + "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "requires": { + "dequal": "^2.0.3" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -34354,9 +34565,9 @@ "version": "1.0.1" }, "cypress": { - "version": "13.7.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.3.tgz", - "integrity": "sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==", + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.10.0.tgz", + "integrity": "sha512-tOhwRlurVOQbMduX+KonoMeQILs2cwR3yHGGENoFvvSoLUBHmJ8b9/n21gFSDqjlOJ+SRVcwuh+fG/JDsHsT6Q==", "dev": true, "requires": { "@cypress/request": "^3.0.0", @@ -34982,6 +35193,12 @@ "depd": { "version": "1.1.2" }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, "des.js": { "version": "1.0.1", "requires": { From 1d04b299143222735eb4aeb8bcfc3410758845d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 18:51:13 +0200 Subject: [PATCH 71/78] change url --- playwright.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright.config.js b/playwright.config.js index 440322997..1c50810c9 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,7 +1,7 @@ // @ts-check const { defineConfig, devices } = require('@playwright/test') -const devBaseUrl = 'http://localhost:5000' +const devBaseUrl = 'http://localhost:8080' module.exports = defineConfig({ testDir: './e2e', From ba5ff7d1ad07026838c8fafabc88fa3643612322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:02:09 +0200 Subject: [PATCH 72/78] test print page --- .github/workflows/playwright.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 199cbf594..16be4507e 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -31,6 +31,9 @@ jobs: run: npx wait-on http://localhost:8080 timeout-minutes: 1 + - name: Print home page + run: curl http://localhost:8080 + - name: Install npm dependencies run: npm install - name: Install dependencies From 72685780047b7e06974906b717fdb7687f212c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:11:58 +0200 Subject: [PATCH 73/78] change tests --- .github/workflows/playwright.yml | 10 +++++----- e2e/ruxailabtest.spec.js | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 16be4507e..b818dd118 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -29,26 +29,26 @@ jobs: - name: Wait for container to become available run: npx wait-on http://localhost:8080 - timeout-minutes: 1 + timeout-minutes: 2 - name: Print home page run: curl http://localhost:8080 - name: Install npm dependencies - run: npm install - - name: Install dependencies run: npm ci + - name: Install Playwright Browsers run: npx playwright install --with-deps + - name: Run Playwright tests run: npx playwright test - - uses: actions/upload-artifact@v4 + + - uses: actions/upload-artifact@v2 if: always() with: name: playwright-report path: playwright-report/ retention-days: 30 - - name: Stop services run: docker-compose down diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index efec65cd8..1963cb38d 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -43,6 +43,8 @@ const createTest = async (page, type) => { test('has link page', async ({ page }) => { await page.goto('/') + // Esperar a que cargue la página + await page.waitForLoadState('domcontentloaded') // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/RUXAILAB/) From 099aae2c04fad1a63e8cb32e44cd0608527690ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:19:04 +0200 Subject: [PATCH 74/78] change tests --- e2e/ruxailabtest.spec.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index 1963cb38d..c0375aeec 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -43,11 +43,12 @@ const createTest = async (page, type) => { test('has link page', async ({ page }) => { await page.goto('/') - // Esperar a que cargue la página - await page.waitForLoadState('domcontentloaded') - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/RUXAILAB/) + // Esperar a que un elemento específico esté presente en la página, indicando que el contenido dinámico se ha cargado + await page.waitForSelector('#app', { timeout: 10000 }) + + // Ahora verificar el título de la página + await expect(page).toHaveTitle(/RUXAILAB/, { timeout: 10000 }) }) // test('sign and create heurisic test', async ({ page }) => { From f701cc29e3a3b9126adcc8555daab7572d600409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:26:02 +0200 Subject: [PATCH 75/78] change tests --- .github/workflows/playwright.yml | 5 +++-- e2e/ruxailabtest.spec.js | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index b818dd118..20e36a476 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -28,8 +28,9 @@ jobs: run: docker-compose up -d --build - name: Wait for container to become available - run: npx wait-on http://localhost:8080 - timeout-minutes: 2 + run: | + npx wait-on http://localhost:8080 + sleep 20 - name: Print home page run: curl http://localhost:8080 diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index c0375aeec..a9862e6a4 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -44,11 +44,14 @@ const createTest = async (page, type) => { test('has link page', async ({ page }) => { await page.goto('/') - // Esperar a que un elemento específico esté presente en la página, indicando que el contenido dinámico se ha cargado - await page.waitForSelector('#app', { timeout: 10000 }) + // Esperar un elemento específico + await page.waitForSelector('#app', { timeout: 20000 }); + + // Tomar una captura de pantalla para verificar el estado de la página + await page.screenshot({ path: 'screenshot.png' }); // Ahora verificar el título de la página - await expect(page).toHaveTitle(/RUXAILAB/, { timeout: 10000 }) + await expect(page).toHaveTitle(/RUXAILAB/, { timeout: 20000 }); }) // test('sign and create heurisic test', async ({ page }) => { From 25f3d67148738e1e22941ab228d820b6279aac8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:34:03 +0200 Subject: [PATCH 76/78] change actions --- .github/workflows/playwright.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 20e36a476..1020ce31b 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,10 @@ jobs: - name: Wait for container to become available run: | npx wait-on http://localhost:8080 - sleep 20 + sleep 30 # Aumenta el tiempo de espera adicional para asegurarte de que el servidor está listo + + - name: Check Docker logs + run: docker-compose logs - name: Print home page run: curl http://localhost:8080 From da257f0c179b1cf68e75279e046377d8b68cb735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:38:31 +0200 Subject: [PATCH 77/78] more tests actions --- .github/workflows/playwright.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 1020ce31b..c308bce6c 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -38,6 +38,12 @@ jobs: - name: Print home page run: curl http://localhost:8080 + - name: Check Docker logs + run: docker-compose logs + + - name: Print product page + run: curl https://ruxailab-dev.web.app + - name: Install npm dependencies run: npm ci From aeada65d924534997787a3d531cc5dfb020f051e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Tue, 4 Jun 2024 19:50:58 +0200 Subject: [PATCH 78/78] change tests --- .github/workflows/playwright.yml | 9 --------- e2e/ruxailabtest.spec.js | 8 ++++---- playwright.config.js | 29 +++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c308bce6c..77ee381ee 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -35,15 +35,6 @@ jobs: - name: Check Docker logs run: docker-compose logs - - name: Print home page - run: curl http://localhost:8080 - - - name: Check Docker logs - run: docker-compose logs - - - name: Print product page - run: curl https://ruxailab-dev.web.app - - name: Install npm dependencies run: npm ci diff --git a/e2e/ruxailabtest.spec.js b/e2e/ruxailabtest.spec.js index a9862e6a4..ff24b37b0 100644 --- a/e2e/ruxailabtest.spec.js +++ b/e2e/ruxailabtest.spec.js @@ -42,16 +42,16 @@ const createTest = async (page, type) => { } test('has link page', async ({ page }) => { - await page.goto('/') + await page.goto('http://localhost:8080/signin') // Esperar un elemento específico - await page.waitForSelector('#app', { timeout: 20000 }); + await page.waitForSelector('#app', { timeout: 20000 }) // Tomar una captura de pantalla para verificar el estado de la página - await page.screenshot({ path: 'screenshot.png' }); + await page.screenshot({ path: 'screenshot.png' }) // Ahora verificar el título de la página - await expect(page).toHaveTitle(/RUXAILAB/, { timeout: 20000 }); + await expect(page).toHaveTitle(/RUXAILAB/, { timeout: 20000 }) }) // test('sign and create heurisic test', async ({ page }) => { diff --git a/playwright.config.js b/playwright.config.js index 1c50810c9..10e1606dc 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,7 +1,7 @@ // @ts-check -const { defineConfig, devices } = require('@playwright/test') +const { defineConfig, devices } = require('@playwright/test'); -const devBaseUrl = 'http://localhost:8080' +const devBaseUrl = 'http://localhost:8080'; module.exports = defineConfig({ testDir: './e2e', @@ -22,13 +22,21 @@ module.exports = defineConfig({ /* Output directory for screenshots of failed tests */ outputDir: './playwright/output', + use: { + baseURL: devBaseUrl, ...devices['Desktop Chrome'], /* Collect trace when retrying the failed test */ trace: 'on-first-retry', /* Create a screenshot if a test fails */ screenshot: { mode: 'only-on-failure', fullPage: true }, + + /* Set global timeout for actions (e.g., click, fill) */ + actionTimeout: 10000, + + /* Set global timeout for navigation */ + navigationTimeout: 30000, }, /* Configure projects for major browsers */ @@ -36,10 +44,23 @@ module.exports = defineConfig({ { name: 'chromium', use: { - baseURL: devBaseUrl, ...devices['Desktop Chrome'], }, retries: 1, }, + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'], + }, + retries: 1, + }, + { + name: 'webkit', + use: { + ...devices['Desktop Safari'], + }, + retries: 1, + }, ], -}) +});