diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..93f7788 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": "next/core-web-vitals" + "extends": [ + "next/core-web-vitals", + "plugin:cypress/recommended" + ] } diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 0000000..78eed99 --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "cypress"; + +export default defineConfig({ + e2e: { + baseUrl: "http://localhost:3000", + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, +}); diff --git a/cypress/e2e/spec.cy.ts b/cypress/e2e/spec.cy.ts new file mode 100644 index 0000000..2dc430c --- /dev/null +++ b/cypress/e2e/spec.cy.ts @@ -0,0 +1,21 @@ +describe("Test all links", () => { + // TODO traverse entire site + it("Test all links on homepage return 200 status", () => { + cy.visit("/"); + cy.get("a").each((page) => { + cy.request(page.prop("href")); + }); + }); + + it("Check navbar links point to correct pathname", () => { + const pages = ["tournois", "about", "contact"]; + + cy.visit("/"); + + pages.forEach((page) => { + cy.contains(page, { matchCase: false }).click(); + cy.location("pathname").should("eq", `/${page}`); // url path matches link name + cy.go("back"); + }); + }); +}); diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts new file mode 100644 index 0000000..698b01a --- /dev/null +++ b/cypress/support/commands.ts @@ -0,0 +1,37 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } \ No newline at end of file diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 0000000..f80f74f --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') \ No newline at end of file diff --git a/cypress/videos/spec.cy.ts.mp4 b/cypress/videos/spec.cy.ts.mp4 new file mode 100644 index 0000000..af79032 Binary files /dev/null and b/cypress/videos/spec.cy.ts.mp4 differ diff --git a/package-lock.json b/package-lock.json index a065cb5..42bfd2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "@testing-library/react": "^14.0.0", "@types/leaflet": "^1.9.3", "cypress": "^12.13.0", + "eslint-plugin-cypress": "^2.13.3", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0" } @@ -3974,6 +3975,27 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-cypress": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.13.3.tgz", + "integrity": "sha512-nAPjZE5WopCsgJwl3vHm5iafpV+ZRO76Z9hMyRygWhmg5ODXDPd+9MaPl7kdJ2azj+sO87H3P1PRnggIrz848g==", + "dev": true, + "dependencies": { + "globals": "^11.12.0" + }, + "peerDependencies": { + "eslint": ">= 3.2.1" + } + }, + "node_modules/eslint-plugin-cypress/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-import": { "version": "2.27.5", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", diff --git a/package.json b/package.json index 40d3f0a..cdcdb65 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,12 @@ "build": "next build", "start": "next start", "lint": "next lint", - "test": "jest --watch" + "jest": "jest", + "jest:watch": "jest --watch", + "cypress:open": "cypress open", + "cypress:run": "cypress run", + "test": "npm run cypress:run && npm run jest", + "test:watch": "npm run cypress:open && npm run jest:watch" }, "dependencies": { "@types/node": "20.2.3", @@ -32,6 +37,7 @@ "@testing-library/react": "^14.0.0", "@types/leaflet": "^1.9.3", "cypress": "^12.13.0", + "eslint-plugin-cypress": "^2.13.3", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0" } diff --git a/utils/layerGroups.tsx b/utils/layerGroups.tsx index 2a333a6..3a7ef39 100644 --- a/utils/layerGroups.tsx +++ b/utils/layerGroups.tsx @@ -12,6 +12,7 @@ export const createLayerGroups = ( (t) => t.time_control === timeControl ); + // TODO consider moving this into its own function const iconOptions = new L.Icon({ iconUrl: `images/leaflet/marker-icon-2x-${colour}.png`, shadowUrl: "images/leaflet/marker-shadow.png", @@ -21,31 +22,31 @@ export const createLayerGroups = ( shadowSize: [41, 41], }); + const layerGroup = filteredTournaments.map((t) => { + // TODO move this coorindate randomisation into its own function to follow SRP + const coordinates = { + lat: t.coordinates[0] + Math.random() * (-0.01 - 0.01) + 0.01, + lng: t.coordinates[1] + Math.random() * (-0.01 - 0.01) + 0.01, + }; + return ( + + + + {t.date} + + + {t.tournament} + + + géolocalisation approximative + + + ); + }); + return ( - - {filteredTournaments.map((t) => { - const coordinates = { - lat: t.coordinates[0] + Math.random() * (-0.01 - 0.01) + 0.01, - lng: t.coordinates[1] + Math.random() * (-0.01 - 0.01) + 0.01, - }; - - return ( - - - - {t.date} - - - {t.tournament} - - - géolocalisation approximative - - - ); - })} - + {layerGroup} ); };
+ {t.date} + + + {t.tournament} + +
- {t.date} - - - {t.tournament} - -