From 7aa5a1ff88f8c540a8716cd16135883aba99eb42 Mon Sep 17 00:00:00 2001 From: Guillaume Charest <1690085+gcharest@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:07:21 +0000 Subject: [PATCH 01/25] feat: add linting workflow for pull requests --- .github/workflows/lint.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..52c0c83 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,24 @@ +name: Lint + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Install dependencies + run: npm ci + - name: Run ESLint + run: npm run lint + - name: Run Markdownlint + run: npx markdownlint '**/*.md' From f32f94a209cc085bd184c8f02d51d2f919cea3a3 Mon Sep 17 00:00:00 2001 From: Guillaume Charest <1690085+gcharest@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:11:06 +0000 Subject: [PATCH 02/25] feat: add paths to deploy static site workflow --- .github/workflows/{static.yml => deploy_static_site.yml} | 8 ++++++++ 1 file changed, 8 insertions(+) rename .github/workflows/{static.yml => deploy_static_site.yml} (90%) diff --git a/.github/workflows/static.yml b/.github/workflows/deploy_static_site.yml similarity index 90% rename from .github/workflows/static.yml rename to .github/workflows/deploy_static_site.yml index 7739663..5ab855f 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/deploy_static_site.yml @@ -5,6 +5,14 @@ on: # Runs on pushes targeting the default branch push: branches: ['main'] + paths: + - 'src/**' + - 'public/**' + - 'package.json' + - 'vite.config.*' + - 'tsconfig.*' + - 'index.html' + - 'env.d.ts' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 6c5eabbe3fe5bfbf4cd6bec9e4d4452d5eb1a992 Mon Sep 17 00:00:00 2001 From: Guillaume Charest <1690085+gcharest@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:20:06 +0000 Subject: [PATCH 03/25] feat: add accessibility tests --- e2e/accessibility.spec.ts | 80 +++++++++++++++++++++++++++++++++++++++ package-lock.json | 25 ++++++++++++ package.json | 3 +- playwright.config.ts | 5 ++- 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 e2e/accessibility.spec.ts diff --git a/e2e/accessibility.spec.ts b/e2e/accessibility.spec.ts new file mode 100644 index 0000000..a029965 --- /dev/null +++ b/e2e/accessibility.spec.ts @@ -0,0 +1,80 @@ +import { test, expect } from '@playwright/test' +import AxeBuilder from '@axe-core/playwright' + +test.describe('Accessibility Tests', () => { + test('Home page should not have any automatically detectable accessibility issues', async ({ page }) => { + await page.goto('/') + const accessibilityScanResults = await new AxeBuilder({ page }).analyze() + expect(accessibilityScanResults.violations).toEqual([]) + }) + + test('Calculator page should not have any automatically detectable accessibility issues', async ({ page }) => { + await page.goto('/calculator') + const accessibilityScanResults = await new AxeBuilder({ page }).analyze() + expect(accessibilityScanResults.violations).toEqual([]) + }) + + test('Carb Factor page should not have any automatically detectable accessibility issues', async ({ page }) => { + await page.goto('/carb-factor') + const accessibilityScanResults = await new AxeBuilder({ page }).analyze() + expect(accessibilityScanResults.violations).toEqual([]) + }) + + test('History page should not have any automatically detectable accessibility issues', async ({ page }) => { + await page.goto('/history') + const accessibilityScanResults = await new AxeBuilder({ page }).analyze() + expect(accessibilityScanResults.violations).toEqual([]) + }) + + test('About page should not have any automatically detectable accessibility issues', async ({ page }) => { + await page.goto('/about') + const accessibilityScanResults = await new AxeBuilder({ page }).analyze() + expect(accessibilityScanResults.violations).toEqual([]) + }) +}) + +// Extended tests for common interactive components +test.describe('Component-specific Accessibility Tests', () => { + test('Navigation menu should be keyboard accessible', async ({ page }) => { + await page.goto('/') + + // Check if the skip link is the first focusable element + await page.keyboard.press('Tab') + const focusedElement = await page.evaluate(() => document.activeElement?.id) + expect(focusedElement).toBe('skip-to-content') + + // Check if the main navigation is accessible + const nav = await page.getByRole('navigation', { name: 'Main navigation' }) + expect(await nav.isVisible()).toBeTruthy() + + // Check for ARIA labels in navigation + const menuButton = await page.getByRole('button', { name: 'Toggle navigation' }) + expect(await menuButton.getAttribute('aria-expanded')).toBe('false') + }) + + test('Language toggler should be properly labeled', async ({ page }) => { + await page.goto('/') + const languageToggler = await page.getByRole('button', { name: /Change Language|Changer la langue/ }) + expect(await languageToggler.isVisible()).toBeTruthy() + }) + + test('Theme toggler should be properly labeled', async ({ page }) => { + await page.goto('/') + const themeToggler = await page.getByRole('button', { name: /Toggle theme|Changer le thème/ }) + expect(await themeToggler.isVisible()).toBeTruthy() + }) + + test('Calculator form controls should be properly labeled', async ({ page }) => { + await page.goto('/calculator') + + // Check if nutrient inputs are properly labeled + const nutrientInputs = await page.getByRole('textbox') + for (const input of await nutrientInputs.all()) { + const label = await input.evaluate(el => { + const id = el.id + return id ? document.querySelector(`label[for="${id}"]`)?.textContent : null + }) + expect(label).toBeTruthy() + } + }) +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d9e9cf5..5fe29fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "gluko", "version": "0.0.0", + "hasInstallScript": true, "dependencies": { "@intlify/unplugin-vue-i18n": "^4.0.0", "@popperjs/core": "^2.11.8", @@ -20,6 +21,7 @@ "vue-router": "^4.5.1" }, "devDependencies": { + "@axe-core/playwright": "^4.10.2", "@eslint/js": "^9.36.0", "@pinia/testing": "^1.0.2", "@playwright/test": "^1.49.1", @@ -82,6 +84,19 @@ "lru-cache": "^10.4.3" } }, + "node_modules/@axe-core/playwright": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.10.2.tgz", + "integrity": "sha512-6/b5BJjG6hDaRNtgzLIfKr5DfwyiLHO4+ByTLB0cJgWSM8Ll7KqtdblIS6bEkwSF642/Ex91vNqIl3GLXGlceg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "axe-core": "~4.10.3" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -4400,6 +4415,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axe-core": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz", + "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", diff --git a/package.json b/package.json index ba8b1f5..c2b2622 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "vue-router": "^4.5.1" }, "devDependencies": { + "@axe-core/playwright": "^4.10.2", "@eslint/js": "^9.36.0", "@pinia/testing": "^1.0.2", "@playwright/test": "^1.49.1", @@ -62,4 +63,4 @@ "vue-eslint-parser": "^10.2.0", "vue-tsc": "^2.1.10" } -} \ No newline at end of file +} diff --git a/playwright.config.ts b/playwright.config.ts index 5531ef5..8529799 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -33,7 +33,10 @@ export default defineConfig({ trace: 'on-first-retry', // Always run headless in the dev container - headless: true + headless: true, + + // Viewport settings that ensure consistent testing + viewport: { width: 1280, height: 720 } }, // Browser configurations From 32f5275f30f4fad65c0881db0d8ca7fe94ece617 Mon Sep 17 00:00:00 2001 From: Guillaume Charest <1690085+gcharest@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:21:28 +0000 Subject: [PATCH 04/25] chore: fmt --- src/components/base/BaseNavigationBar.vue | 83 +++++++++--- src/components/base/BaseNotice.vue | 10 +- src/components/base/BaseThemeToggler.vue | 35 +++-- .../calculator/CalculatorControls.vue | 2 +- .../calculator/CalculatorSummary.vue | 2 +- src/components/calculator/MealCalculator.vue | 36 +++--- src/components/filters/DateRangeFilter.vue | 35 +++-- src/components/filters/SubjectSelector.vue | 31 +++-- src/components/history/MealHistoryCard.vue | 22 ++-- src/components/modals/ConfirmationModal.vue | 35 +++-- src/components/modals/NutrientModal.vue | 120 ++++++++++++------ src/components/nutrients/NutrientList.vue | 29 +++-- src/components/nutrients/NutrientListItem.vue | 61 ++++++--- src/components/search/CarbFactorSearch.vue | 35 +++-- src/components/search/NutrientSearch.vue | 8 +- src/components/search/SearchResults.vue | 24 ++-- src/composables/useIndexedDB.ts | 74 ++++++----- src/i18n/locales/en.json | 2 +- src/i18n/locales/fr.json | 2 +- src/stores/meal.ts | 33 ++--- src/stores/mealHistory.ts | 55 ++++---- src/stores/nutrientsFile.ts | 4 +- src/stores/session.ts | 4 +- src/stores/subject.ts | 26 ++-- src/types/meal-history.ts | 2 +- src/views/CalculatorView.vue | 2 +- src/views/CarbFactor.vue | 2 +- src/views/HomeView.vue | 7 +- src/views/MealHistoryView.vue | 45 +++++-- 29 files changed, 551 insertions(+), 275 deletions(-) diff --git a/src/components/base/BaseNavigationBar.vue b/src/components/base/BaseNavigationBar.vue index b9e13e7..4c2c192 100644 --- a/src/components/base/BaseNavigationBar.vue +++ b/src/components/base/BaseNavigationBar.vue @@ -19,44 +19,91 @@ const mainNavigationBarAriaLabel = ref(t('navigation.mainNavigation'))